Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relax implicit T: Sized bounds on BufReader<T>, BufWriter<T> and LineWriter<T> #111074

Merged
merged 3 commits into from
Jun 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions library/std/src/io/buffered/bufreader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ use buffer::Buffer;
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufReader<R> {
inner: R,
pub struct BufReader<R: ?Sized> {
buf: Buffer,
inner: R,
}

impl<R: Read> BufReader<R> {
Expand Down Expand Up @@ -95,7 +95,7 @@ impl<R: Read> BufReader<R> {
}
}

impl<R> BufReader<R> {
impl<R: ?Sized> BufReader<R> {
/// Gets a reference to the underlying reader.
///
/// It is inadvisable to directly read from the underlying reader.
Expand Down Expand Up @@ -213,7 +213,10 @@ impl<R> BufReader<R> {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(self) -> R {
pub fn into_inner(self) -> R
where
R: Sized,
{
self.inner
}

Expand All @@ -226,13 +229,13 @@ impl<R> BufReader<R> {

// This is only used by a test which asserts that the initialization-tracking is correct.
#[cfg(test)]
impl<R> BufReader<R> {
impl<R: ?Sized> BufReader<R> {
pub fn initialized(&self) -> usize {
self.buf.initialized()
}
}

impl<R: Seek> BufReader<R> {
impl<R: ?Sized + Seek> BufReader<R> {
/// Seeks relative to the current position. If the new position lies within the buffer,
/// the buffer will not be flushed, allowing for more efficient seeks.
/// This method does not return the location of the underlying reader, so the caller
Expand All @@ -257,7 +260,7 @@ impl<R: Seek> BufReader<R> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read> Read for BufReader<R> {
impl<R: ?Sized + Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
Expand Down Expand Up @@ -371,7 +374,7 @@ impl<R: Read> Read for BufReader<R> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read> BufRead for BufReader<R> {
impl<R: ?Sized + Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.buf.fill_buf(&mut self.inner)
}
Expand All @@ -384,11 +387,11 @@ impl<R: Read> BufRead for BufReader<R> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<R> fmt::Debug for BufReader<R>
where
R: fmt::Debug,
R: ?Sized + fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufReader")
.field("reader", &self.inner)
.field("reader", &&self.inner)
.field(
"buffer",
&format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()),
Expand All @@ -398,7 +401,7 @@ where
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Seek> Seek for BufReader<R> {
impl<R: ?Sized + Seek> Seek for BufReader<R> {
/// Seek to an offset, in bytes, in the underlying reader.
///
/// The position used for seeking with <code>[SeekFrom::Current]\(_)</code> is the
Expand Down Expand Up @@ -491,7 +494,7 @@ impl<R: Seek> Seek for BufReader<R> {
}
}

impl<T> SizeHint for BufReader<T> {
impl<T: ?Sized> SizeHint for BufReader<T> {
#[inline]
fn lower_bound(&self) -> usize {
SizeHint::lower_bound(self.get_ref()) + self.buffer().len()
Expand Down
138 changes: 70 additions & 68 deletions library/std/src/io/buffered/bufwriter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ use crate::ptr;
/// [`TcpStream`]: crate::net::TcpStream
/// [`flush`]: BufWriter::flush
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufWriter<W: Write> {
inner: W,
pub struct BufWriter<W: ?Sized + Write> {
// The buffer. Avoid using this like a normal `Vec` in common code paths.
// That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
// methods that require bounds checking or the like. This makes an enormous
Expand All @@ -78,6 +77,7 @@ pub struct BufWriter<W: Write> {
// write the buffered data a second time in BufWriter's destructor. This
// flag tells the Drop impl if it should skip the flush.
panicked: bool,
inner: W,
}

impl<W: Write> BufWriter<W> {
Expand Down Expand Up @@ -115,6 +115,69 @@ impl<W: Write> BufWriter<W> {
BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false }
}

/// Unwraps this `BufWriter<W>`, returning the underlying writer.
///
/// The buffer is written out before returning the writer.
///
/// # Errors
///
/// An [`Err`] will be returned if an error occurs while flushing the buffer.
///
/// # Examples
///
/// ```no_run
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // unwrap the TcpStream and flush the buffer
/// let stream = buffer.into_inner().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
match self.flush_buf() {
Err(e) => Err(IntoInnerError::new(self, e)),
Ok(()) => Ok(self.into_parts().0),
}
}

/// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
/// unwritten data.
///
/// If the underlying writer panicked, it is not known what portion of the data was written.
/// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
/// contents can still be recovered).
///
/// `into_parts` makes no attempt to flush data and cannot fail.
///
/// # Examples
///
/// ```
/// use std::io::{BufWriter, Write};
///
/// let mut buffer = [0u8; 10];
/// let mut stream = BufWriter::new(buffer.as_mut());
/// write!(stream, "too much data").unwrap();
/// stream.flush().expect_err("it doesn't fit");
/// let (recovered_writer, buffered_data) = stream.into_parts();
/// assert_eq!(recovered_writer.len(), 0);
/// assert_eq!(&buffered_data.unwrap(), b"ata");
/// ```
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
let buf = mem::take(&mut self.buf);
let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };

// SAFETY: forget(self) prevents double dropping inner
let inner = unsafe { ptr::read(&self.inner) };
mem::forget(self);

(inner, buf)
}
}

impl<W: ?Sized + Write> BufWriter<W> {
/// Send data in our local buffer into the inner writer, looping as
/// necessary until either it's all been sent or an error occurs.
///
Expand Down Expand Up @@ -284,67 +347,6 @@ impl<W: Write> BufWriter<W> {
self.buf.capacity()
}

/// Unwraps this `BufWriter<W>`, returning the underlying writer.
///
/// The buffer is written out before returning the writer.
///
/// # Errors
///
/// An [`Err`] will be returned if an error occurs while flushing the buffer.
///
/// # Examples
///
/// ```no_run
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // unwrap the TcpStream and flush the buffer
/// let stream = buffer.into_inner().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
match self.flush_buf() {
Err(e) => Err(IntoInnerError::new(self, e)),
Ok(()) => Ok(self.into_parts().0),
}
}

/// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
/// unwritten data.
///
/// If the underlying writer panicked, it is not known what portion of the data was written.
/// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
/// contents can still be recovered).
///
/// `into_parts` makes no attempt to flush data and cannot fail.
///
/// # Examples
///
/// ```
/// use std::io::{BufWriter, Write};
///
/// let mut buffer = [0u8; 10];
/// let mut stream = BufWriter::new(buffer.as_mut());
/// write!(stream, "too much data").unwrap();
/// stream.flush().expect_err("it doesn't fit");
/// let (recovered_writer, buffered_data) = stream.into_parts();
/// assert_eq!(recovered_writer.len(), 0);
/// assert_eq!(&buffered_data.unwrap(), b"ata");
/// ```
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
let buf = mem::take(&mut self.buf);
let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };

// SAFETY: forget(self) prevents double dropping inner
let inner = unsafe { ptr::read(&self.inner) };
mem::forget(self);

(inner, buf)
}

// Ensure this function does not get inlined into `write`, so that it
// remains inlineable and its common path remains as short as possible.
// If this function ends up being called frequently relative to `write`,
Expand Down Expand Up @@ -511,7 +513,7 @@ impl fmt::Debug for WriterPanicked {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Write for BufWriter<W> {
impl<W: ?Sized + Write> Write for BufWriter<W> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// Use < instead of <= to avoid a needless trip through the buffer in some cases.
Expand Down Expand Up @@ -640,20 +642,20 @@ impl<W: Write> Write for BufWriter<W> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> fmt::Debug for BufWriter<W>
impl<W: ?Sized + Write> fmt::Debug for BufWriter<W>
where
W: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufWriter")
.field("writer", &self.inner)
.field("writer", &&self.inner)
.field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
.finish()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write + Seek> Seek for BufWriter<W> {
impl<W: ?Sized + Write + Seek> Seek for BufWriter<W> {
/// Seek to the offset, in bytes, in the underlying writer.
///
/// Seeking always writes out the internal buffer before seeking.
Expand All @@ -664,7 +666,7 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Drop for BufWriter<W> {
impl<W: ?Sized + Write> Drop for BufWriter<W> {
fn drop(&mut self) {
if !self.panicked {
// dtors should not panic, so we ignore a failed flush
Expand Down
50 changes: 26 additions & 24 deletions library/std/src/io/buffered/linewriter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSli
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LineWriter<W: Write> {
pub struct LineWriter<W: ?Sized + Write> {
inner: BufWriter<W>,
}

Expand Down Expand Up @@ -109,27 +109,6 @@ impl<W: Write> LineWriter<W> {
LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
}

/// Gets a reference to the underlying writer.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::io::LineWriter;
///
/// fn main() -> std::io::Result<()> {
/// let file = File::create("poem.txt")?;
/// let file = LineWriter::new(file);
///
/// let reference = file.get_ref();
/// Ok(())
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_ref(&self) -> &W {
self.inner.get_ref()
}

/// Gets a mutable reference to the underlying writer.
///
/// Caution must be taken when calling methods on the mutable reference
Expand Down Expand Up @@ -184,8 +163,31 @@ impl<W: Write> LineWriter<W> {
}
}

impl<W: ?Sized + Write> LineWriter<W> {
/// Gets a reference to the underlying writer.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::io::LineWriter;
///
/// fn main() -> std::io::Result<()> {
/// let file = File::create("poem.txt")?;
/// let file = LineWriter::new(file);
///
/// let reference = file.get_ref();
/// Ok(())
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_ref(&self) -> &W {
self.inner.get_ref()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Write for LineWriter<W> {
impl<W: ?Sized + Write> Write for LineWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
LineWriterShim::new(&mut self.inner).write(buf)
}
Expand Down Expand Up @@ -216,7 +218,7 @@ impl<W: Write> Write for LineWriter<W> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> fmt::Debug for LineWriter<W>
impl<W: ?Sized + Write> fmt::Debug for LineWriter<W>
where
W: fmt::Debug,
{
Expand Down
6 changes: 3 additions & 3 deletions library/std/src/io/buffered/linewritershim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use crate::sys_common::memchr;
/// `BufWriters` to be temporarily given line-buffering logic; this is what
/// enables Stdout to be alternately in line-buffered or block-buffered mode.
#[derive(Debug)]
pub struct LineWriterShim<'a, W: Write> {
pub struct LineWriterShim<'a, W: ?Sized + Write> {
buffer: &'a mut BufWriter<W>,
}

impl<'a, W: Write> LineWriterShim<'a, W> {
impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
Self { buffer }
}
Expand Down Expand Up @@ -49,7 +49,7 @@ impl<'a, W: Write> LineWriterShim<'a, W> {
}
}

impl<'a, W: Write> Write for LineWriterShim<'a, W> {
impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
/// Write some data into this BufReader with line buffering. This means
/// that, if any newlines are present in the data, the data up to the last
/// newline is sent directly to the underlying writer, and data after it
Expand Down
Loading