diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 4f339a18a480e..3edf9d747ce89 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -47,9 +47,9 @@ use buffer::Buffer; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct BufReader { - inner: R, +pub struct BufReader { buf: Buffer, + inner: R, } impl BufReader { @@ -95,7 +95,7 @@ impl BufReader { } } -impl BufReader { +impl BufReader { /// Gets a reference to the underlying reader. /// /// It is inadvisable to directly read from the underlying reader. @@ -213,7 +213,10 @@ impl BufReader { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> R { + pub fn into_inner(self) -> R + where + R: Sized, + { self.inner } @@ -226,13 +229,13 @@ impl BufReader { // This is only used by a test which asserts that the initialization-tracking is correct. #[cfg(test)] -impl BufReader { +impl BufReader { pub fn initialized(&self) -> usize { self.buf.initialized() } } -impl BufReader { +impl BufReader { /// 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 @@ -257,7 +260,7 @@ impl BufReader { } #[stable(feature = "rust1", since = "1.0.0")] -impl Read for BufReader { +impl Read for BufReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { // If we don't have any buffered data and we're doing a massive read // (larger than our internal buffer), bypass our internal buffer @@ -371,7 +374,7 @@ impl Read for BufReader { } #[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for BufReader { +impl BufRead for BufReader { fn fill_buf(&mut self) -> io::Result<&[u8]> { self.buf.fill_buf(&mut self.inner) } @@ -384,11 +387,11 @@ impl BufRead for BufReader { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for BufReader 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()), @@ -398,7 +401,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Seek for BufReader { +impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// /// The position used for seeking with [SeekFrom::Current]\(_) is the @@ -491,7 +494,7 @@ impl Seek for BufReader { } } -impl SizeHint for BufReader { +impl SizeHint for BufReader { #[inline] fn lower_bound(&self) -> usize { SizeHint::lower_bound(self.get_ref()) + self.buffer().len() diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 14c455d4fa3c9..0e2450655e5bf 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -67,8 +67,7 @@ use crate::ptr; /// [`TcpStream`]: crate::net::TcpStream /// [`flush`]: BufWriter::flush #[stable(feature = "rust1", since = "1.0.0")] -pub struct BufWriter { - inner: W, +pub struct BufWriter { // 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 @@ -78,6 +77,7 @@ pub struct BufWriter { // 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 BufWriter { @@ -115,6 +115,69 @@ impl BufWriter { BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false } } + /// Unwraps this `BufWriter`, 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>> { + match self.flush_buf() { + Err(e) => Err(IntoInnerError::new(self, e)), + Ok(()) => Ok(self.into_parts().0), + } + } + + /// Disassembles this `BufWriter`, 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, 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 BufWriter { /// Send data in our local buffer into the inner writer, looping as /// necessary until either it's all been sent or an error occurs. /// @@ -284,67 +347,6 @@ impl BufWriter { self.buf.capacity() } - /// Unwraps this `BufWriter`, 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>> { - match self.flush_buf() { - Err(e) => Err(IntoInnerError::new(self, e)), - Ok(()) => Ok(self.into_parts().0), - } - } - - /// Disassembles this `BufWriter`, 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, 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`, @@ -511,7 +513,7 @@ impl fmt::Debug for WriterPanicked { } #[stable(feature = "rust1", since = "1.0.0")] -impl Write for BufWriter { +impl Write for BufWriter { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { // Use < instead of <= to avoid a needless trip through the buffer in some cases. @@ -640,20 +642,20 @@ impl Write for BufWriter { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufWriter +impl fmt::Debug for BufWriter 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 Seek for BufWriter { +impl Seek for BufWriter { /// Seek to the offset, in bytes, in the underlying writer. /// /// Seeking always writes out the internal buffer before seeking. @@ -664,7 +666,7 @@ impl Seek for BufWriter { } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for BufWriter { +impl Drop for BufWriter { fn drop(&mut self) { if !self.panicked { // dtors should not panic, so we ignore a failed flush diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs index a26a4ab330e7a..3d4ae70419322 100644 --- a/library/std/src/io/buffered/linewriter.rs +++ b/library/std/src/io/buffered/linewriter.rs @@ -64,7 +64,7 @@ use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSli /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct LineWriter { +pub struct LineWriter { inner: BufWriter, } @@ -109,27 +109,6 @@ impl LineWriter { 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 @@ -184,8 +163,31 @@ impl LineWriter { } } +impl LineWriter { + /// 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 Write for LineWriter { +impl Write for LineWriter { fn write(&mut self, buf: &[u8]) -> io::Result { LineWriterShim::new(&mut self.inner).write(buf) } @@ -216,7 +218,7 @@ impl Write for LineWriter { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LineWriter +impl fmt::Debug for LineWriter where W: fmt::Debug, { diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs index 0175d2693e894..f2a55da05b22e 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/std/src/io/buffered/linewritershim.rs @@ -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, } -impl<'a, W: Write> LineWriterShim<'a, W> { +impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> { pub fn new(buffer: &'a mut BufWriter) -> Self { Self { buffer } } @@ -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 diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 1d9d93f5b64ec..420fc4007050b 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -86,7 +86,7 @@ impl BufferedCopySpec for W { } } -impl BufferedCopySpec for BufWriter { +impl BufferedCopySpec for BufWriter { fn copy_to(reader: &mut R, writer: &mut Self) -> Result { if writer.capacity() < DEFAULT_BUF_SIZE { return stack_buffer_copy(reader, writer); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 8a007d095d5e3..173233d7150b2 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2754,7 +2754,7 @@ trait SizeHint { } } -impl SizeHint for T { +impl SizeHint for T { #[inline] default fn lower_bound(&self) -> usize { 0 diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 16c8e0c0ebfc5..7d49bbdcbe063 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -466,7 +466,7 @@ impl CopyRead for Take { } } -impl CopyRead for BufReader { +impl CopyRead for BufReader { fn drain_to(&mut self, writer: &mut W, outer_limit: u64) -> Result { let buf = self.buffer(); let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))]; @@ -495,7 +495,7 @@ impl CopyRead for BufReader { } } -impl CopyWrite for BufWriter { +impl CopyWrite for BufWriter { fn properties(&self) -> CopyParams { self.get_ref().properties() }