diff --git a/library/std/src/io/buffered/bufreader.rs b/library/alloc/src/io/buffered/bufreader.rs similarity index 87% rename from library/std/src/io/buffered/bufreader.rs rename to library/alloc/src/io/buffered/bufreader.rs index 8d122c8e76e5f..9a912be8e18f0 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/alloc/src/io/buffered/bufreader.rs @@ -1,12 +1,14 @@ mod buffer; -use buffer::Buffer; +pub(super) use buffer::Buffer; use crate::fmt; use crate::io::{ self, BorrowedCursor, BufRead, DEFAULT_BUF_SIZE, IoSliceMut, Read, Seek, SeekFrom, SizeHint, SpecReadByte, uninlined_slow_read_byte, }; +use crate::string::String; +use crate::vec::Vec; /// The `BufReader` struct adds buffering to any reader. /// @@ -27,8 +29,9 @@ use crate::io::{ /// unwrapping the `BufReader` with [`BufReader::into_inner`] can also cause /// data loss. /// -/// [`TcpStream::read`]: crate::net::TcpStream::read -/// [`TcpStream`]: crate::net::TcpStream +// FIXME(#74481): Hard-links required to link from `alloc` to `std` +/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples /// @@ -70,16 +73,21 @@ impl BufReader { /// Ok(()) /// } /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: R) -> BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } - pub(crate) fn try_new_buffer() -> io::Result { + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + pub fn try_new_buffer() -> io::Result { Buffer::try_with_capacity(DEFAULT_BUF_SIZE) } - pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self { + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + pub fn with_buffer(inner: R, buf: Buffer) -> Self { Self { inner, buf } } @@ -99,6 +107,7 @@ impl BufReader { /// Ok(()) /// } /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: R) -> BufReader { BufReader { inner, buf: Buffer::with_capacity(capacity) } @@ -280,14 +289,17 @@ impl BufReader { /// Invalidates all data in the internal buffer. #[inline] - pub(in crate::io) fn discard_buffer(&mut self) { + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + pub fn discard_buffer(&mut self) { self.buf.discard_buffer() } } // This is only used by a test which asserts that the initialization-tracking is correct. -#[cfg(test)] impl BufReader { + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] #[allow(missing_docs)] pub fn initialized(&self) -> bool { self.buf.initialized() @@ -413,7 +425,28 @@ impl Read for BufReader { fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { let inner_buf = self.buffer(); buf.try_reserve(inner_buf.len())?; - buf.extend_from_slice(inner_buf); + + cfg_select! { + no_global_oom_handling => { + // SAFETY: + // * inner_buf and buf are non-overlapping + // * buf[..len] is already initialized + // * buf[len..len + count] is initialized by copy_nonoverlapping + // * len + count is within the capacity of buf based on the reservation completed above + unsafe { + let count = inner_buf.len(); + let len = buf.len(); + let src = inner_buf.as_ptr(); + let dst = buf.as_mut_ptr().add(len); + core::ptr::copy_nonoverlapping(src, dst, count); + buf.set_len(len + count); + } + } + _ => { + buf.extend_from_slice(inner_buf); + } + } + let nread = inner_buf.len(); self.discard_buffer(); Ok(nread + self.inner.read_to_end(buf)?) @@ -445,7 +478,31 @@ impl Read for BufReader { let mut bytes = Vec::new(); self.read_to_end(&mut bytes)?; let string = crate::str::from_utf8(&bytes).map_err(|_| io::Error::INVALID_UTF8)?; - *buf += string; + + cfg_select! { + no_global_oom_handling => { + // SAFETY: + // * string and buf are non-overlapping + // * buf[..len] is already initialized + // * buf[len..len + count] is initialized by copy_nonoverlapping + // * len + count is within the capacity of buf based on the reservation completed above + // * buf is appended with valid UTF-8 data and is initially valid UTF-8, therefore + // it is valid UTF-8 at all times. + unsafe { + let buf = buf.as_mut_vec(); + let count = string.len(); + let len = buf.len(); + let src = string.as_ptr(); + let dst = buf.as_mut_ptr().add(len); + core::ptr::copy_nonoverlapping(src, dst, count); + buf.set_len(len + count); + } + } + _ => { + *buf += string; + } + } + Ok(string.len()) } } diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/alloc/src/io/buffered/bufreader/buffer.rs similarity index 82% rename from library/std/src/io/buffered/bufreader/buffer.rs rename to library/alloc/src/io/buffered/bufreader/buffer.rs index f2efcc5ab8601..3c88e705c7011 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/alloc/src/io/buffered/bufreader/buffer.rs @@ -9,10 +9,15 @@ //! that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so //! without encountering any runtime bounds checks. -use crate::cmp; +use core::cmp; +use core::mem::MaybeUninit; + +use crate::boxed::Box; use crate::io::{self, BorrowedBuf, ErrorKind, Read}; -use crate::mem::MaybeUninit; +#[doc(hidden)] +#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] +#[derive(Debug)] pub struct Buffer { // The buffer. buf: Box<[MaybeUninit]>, @@ -29,14 +34,15 @@ pub struct Buffer { } impl Buffer { + #[cfg(not(no_global_oom_handling))] #[inline] - pub fn with_capacity(capacity: usize) -> Self { + pub(super) fn with_capacity(capacity: usize) -> Self { let buf = Box::new_uninit_slice(capacity); Self { buf, pos: 0, filled: 0, initialized: false } } #[inline] - pub fn try_with_capacity(capacity: usize) -> io::Result { + pub(super) fn try_with_capacity(capacity: usize) -> io::Result { match Box::try_new_uninit_slice(capacity) { Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: false }), Err(_) => { @@ -46,48 +52,47 @@ impl Buffer { } #[inline] - pub fn buffer(&self) -> &[u8] { + pub(super) fn buffer(&self) -> &[u8] { // SAFETY: self.pos and self.filled are valid, and self.filled >= self.pos, and // that region is initialized because those are all invariants of this type. unsafe { self.buf.get_unchecked(self.pos..self.filled).assume_init_ref() } } #[inline] - pub fn capacity(&self) -> usize { + pub(super) fn capacity(&self) -> usize { self.buf.len() } #[inline] - pub fn filled(&self) -> usize { + pub(super) fn filled(&self) -> usize { self.filled } #[inline] - pub fn pos(&self) -> usize { + pub(super) fn pos(&self) -> usize { self.pos } // This is only used by a test which asserts that the initialization-tracking is correct. - #[cfg(test)] - pub fn initialized(&self) -> bool { + pub(super) fn initialized(&self) -> bool { self.initialized } #[inline] - pub fn discard_buffer(&mut self) { + pub(super) fn discard_buffer(&mut self) { self.pos = 0; self.filled = 0; } #[inline] - pub fn consume(&mut self, amt: usize) { + pub(super) fn consume(&mut self, amt: usize) { self.pos = cmp::min(self.pos + amt, self.filled); } /// If there are `amt` bytes available in the buffer, pass a slice containing those bytes to /// `visitor` and return true. If there are not enough bytes available, return false. #[inline] - pub fn consume_with(&mut self, amt: usize, mut visitor: V) -> bool + pub(super) fn consume_with(&mut self, amt: usize, mut visitor: V) -> bool where V: FnMut(&[u8]), { @@ -102,12 +107,12 @@ impl Buffer { } #[inline] - pub fn unconsume(&mut self, amt: usize) { + pub(super) fn unconsume(&mut self, amt: usize) { self.pos = self.pos.saturating_sub(amt); } /// Read more bytes into the buffer without discarding any of its contents - pub fn read_more(&mut self, mut reader: impl Read) -> io::Result { + pub(super) fn read_more(&mut self, mut reader: impl Read) -> io::Result { let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]); if self.initialized { @@ -124,14 +129,14 @@ impl Buffer { } /// Remove bytes that have already been read from the buffer. - pub fn backshift(&mut self) { + pub(super) fn backshift(&mut self) { self.buf.copy_within(self.pos..self.filled, 0); self.filled -= self.pos; self.pos = 0; } #[inline] - pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> { + pub(super) fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> { // If we've reached the end of our internal buffer then we need to fetch // some more data from the reader. // Branch using `>=` instead of the more correct `==` diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/alloc/src/io/buffered/bufwriter.rs similarity index 95% rename from library/std/src/io/buffered/bufwriter.rs rename to library/alloc/src/io/buffered/bufwriter.rs index 1a5cc911c0e43..59fa1f230fd3c 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/alloc/src/io/buffered/bufwriter.rs @@ -1,8 +1,10 @@ +use core::mem::{self, ManuallyDrop}; +use core::{error, fmt, ptr}; + use crate::io::{ self, DEFAULT_BUF_SIZE, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, }; -use crate::mem::{self, ManuallyDrop}; -use crate::{error, fmt, ptr}; +use crate::vec::Vec; /// Wraps a writer and buffers its output. /// @@ -60,8 +62,9 @@ use crate::{error, fmt, ptr}; /// together by the buffer and will all be written out in one system call when /// the `stream` is flushed. /// -/// [`TcpStream::write`]: crate::net::TcpStream::write -/// [`TcpStream`]: crate::net::TcpStream +// FIXME(#74481): Hard-links required to link from `alloc` to `std` +/// [`TcpStream::write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// [`flush`]: BufWriter::flush #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { @@ -87,20 +90,26 @@ impl BufWriter { /// use std::io::BufWriter; /// use std::net::TcpStream; /// + /// # #[expect(unused_mut)] /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - pub(crate) fn try_new_buffer() -> io::Result> { + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + pub fn try_new_buffer() -> io::Result> { Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| { io::const_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer") }) } - pub(crate) fn with_buffer(inner: W, buf: Vec) -> Self { + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + pub fn with_buffer(inner: W, buf: Vec) -> Self { Self { inner, buf, panicked: false } } @@ -115,8 +124,10 @@ impl BufWriter { /// use std::net::TcpStream; /// /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// # #[expect(unused_mut)] /// let mut buffer = BufWriter::with_capacity(100, stream); /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: W) -> BufWriter { BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false } @@ -136,6 +147,7 @@ impl BufWriter { /// use std::io::BufWriter; /// use std::net::TcpStream; /// + /// # #[expect(unused_mut)] /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); /// /// // unwrap the TcpStream and flush the buffer @@ -192,7 +204,9 @@ impl BufWriter { /// "successfully written" (by returning nonzero success values from /// `write`), any 0-length writes from `inner` must be reported as i/o /// errors from this method. - pub(in crate::io) fn flush_buf(&mut self) -> io::Result<()> { + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + pub fn flush_buf(&mut self) -> io::Result<()> { // SAFETY: `::copy_from` assumes that // this will not de-initialize any elements of `self.buf`'s spare // capacity. @@ -287,6 +301,7 @@ impl BufWriter { /// use std::io::BufWriter; /// use std::net::TcpStream; /// + /// # #[expect(unused_mut)] /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); /// /// // we can use reference just like buffer @@ -343,7 +358,9 @@ impl BufWriter { /// That the buffer is a `Vec` is an implementation detail. /// Callers should not modify the capacity as there currently is no public API to do so /// and thus any capacity changes would be unexpected by the user. - pub(in crate::io) fn buffer_mut(&mut self) -> &mut Vec { + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + pub fn buffer_mut(&mut self) -> &mut Vec { &mut self.buf } diff --git a/library/std/src/io/buffered/linewriter.rs b/library/alloc/src/io/buffered/linewriter.rs similarity index 98% rename from library/std/src/io/buffered/linewriter.rs rename to library/alloc/src/io/buffered/linewriter.rs index cc6921b86dd0b..bdb979e931f2e 100644 --- a/library/std/src/io/buffered/linewriter.rs +++ b/library/alloc/src/io/buffered/linewriter.rs @@ -84,6 +84,7 @@ impl LineWriter { /// Ok(()) /// } /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> LineWriter { // Lines typically aren't that long, don't use a giant buffer @@ -105,6 +106,7 @@ impl LineWriter { /// Ok(()) /// } /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: W) -> LineWriter { LineWriter { inner: BufWriter::with_capacity(capacity, inner) } diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/alloc/src/io/buffered/linewritershim.rs similarity index 99% rename from library/std/src/io/buffered/linewritershim.rs rename to library/alloc/src/io/buffered/linewritershim.rs index fc250e6ab7de9..35f448fc3aa8a 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/alloc/src/io/buffered/linewritershim.rs @@ -13,12 +13,12 @@ use crate::io::{self, BufWriter, IoSlice, Write}; /// `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: ?Sized + Write> { +pub(super) struct LineWriterShim<'a, W: ?Sized + Write> { buffer: &'a mut BufWriter, } impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> { - pub fn new(buffer: &'a mut BufWriter) -> Self { + pub(super) fn new(buffer: &'a mut BufWriter) -> Self { Self { buffer } } diff --git a/library/alloc/src/io/buffered/mod.rs b/library/alloc/src/io/buffered/mod.rs new file mode 100644 index 0000000000000..1bddcfb801932 --- /dev/null +++ b/library/alloc/src/io/buffered/mod.rs @@ -0,0 +1,189 @@ +//! Buffering wrappers for I/O traits + +mod bufreader; +mod bufwriter; +mod linewriter; +mod linewritershim; + +use core::{error, fmt}; + +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] +pub use self::bufwriter::WriterPanicked; +use self::linewritershim::LineWriterShim; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter}; +use crate::io::Error; + +/// An error returned by [`BufWriter::into_inner`] which combines an error that +/// happened while writing out the buffer, and the buffered writer object +/// which may be used to recover from the condition. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// # #[expect(unused_mut)] +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// // do stuff with the stream +/// +/// // we want to get our `TcpStream` back, so let's try: +/// +/// let stream = match stream.into_inner() { +/// Ok(s) => s, +/// Err(e) => { +/// // Here, e is an IntoInnerError +/// panic!("An error occurred"); +/// } +/// }; +/// ``` +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoInnerError(W, Error); + +impl IntoInnerError { + /// Constructs a new IntoInnerError + fn new(writer: W, error: Error) -> Self { + Self(writer, error) + } + + /// Helper to construct a new IntoInnerError; intended to help with + /// adapters that wrap other adapters + fn new_wrapped(self, f: impl FnOnce(W) -> W2) -> IntoInnerError { + let Self(writer, error) = self; + IntoInnerError::new(f(writer), error) + } + + /// Returns the error which caused the call to [`BufWriter::into_inner()`] + /// to fail. + /// + /// This error was returned when attempting to write the internal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// # #[expect(unused_mut)] + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's log the inner error. + /// // + /// // We'll just 'log' to stdout for this example. + /// println!("{}", e.error()); + /// + /// panic!("An unexpected error occurred."); + /// } + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn error(&self) -> &Error { + &self.1 + } + + /// Returns the buffered writer instance which generated the error. + /// + /// The returned object can be used for error recovery, such as + /// re-inspecting the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// # #[expect(unused_mut)] + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's re-examine the buffer: + /// let buffer = e.into_inner(); + /// + /// // do stuff to try to recover + /// + /// // afterwards, let's just return the stream + /// buffer.into_inner().unwrap() + /// } + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> W { + self.0 + } + + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to + /// [`BufWriter::into_inner()`] to fail. Unlike `error`, this can be used to + /// obtain ownership of the underlying error. + /// + /// # Example + /// ``` + /// use std::io::{BufWriter, ErrorKind, Write}; + /// + /// let mut not_enough_space = [0u8; 10]; + /// let mut stream = BufWriter::new(not_enough_space.as_mut()); + /// write!(stream, "this cannot be actually written").unwrap(); + /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); + /// let err = into_inner_err.into_error(); + /// assert_eq!(err.kind(), ErrorKind::WriteZero); + /// ``` + #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")] + pub fn into_error(self) -> Error { + self.1 + } + + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to + /// [`BufWriter::into_inner()`] to fail, and the underlying writer. + /// + /// This can be used to simply obtain ownership of the underlying error; it can also be used for + /// advanced error recovery. + /// + /// # Example + /// ``` + /// use std::io::{BufWriter, ErrorKind, Write}; + /// + /// let mut not_enough_space = [0u8; 10]; + /// let mut stream = BufWriter::new(not_enough_space.as_mut()); + /// write!(stream, "this cannot be actually written").unwrap(); + /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); + /// let (err, recovered_writer) = into_inner_err.into_parts(); + /// assert_eq!(err.kind(), ErrorKind::WriteZero); + /// assert_eq!(recovered_writer.buffer(), b"t be actually written"); + /// ``` + #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")] + pub fn into_parts(self) -> (Error, W) { + (self.1, self.0) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From> for Error { + fn from(iie: IntoInnerError) -> Error { + iie.1 + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl error::Error for IntoInnerError {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for IntoInnerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.error().fmt(f) + } +} diff --git a/library/alloc/src/io/copy.rs b/library/alloc/src/io/copy.rs new file mode 100644 index 0000000000000..e00105b0378da --- /dev/null +++ b/library/alloc/src/io/copy.rs @@ -0,0 +1,238 @@ +use core::cmp; +use core::mem::MaybeUninit; + +#[cfg(not(no_global_oom_handling))] +use crate::collections::VecDeque; +use crate::io::{BorrowedBuf, BufReader, BufWriter, DEFAULT_BUF_SIZE, Read, Result, Write}; +use crate::vec::Vec; +#[cfg_attr( + no_global_oom_handling, + expect(unused_imports, reason = "only required for VecDeque specialization") +)] +use crate::{alloc::Allocator, io::IoSlice}; + +/// The userspace read-write-loop implementation of `io::copy` that is used when +/// OS-specific specializations for copy offloading are not available or not applicable. +#[doc(hidden)] +#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] +pub fn generic_copy(reader: &mut R, writer: &mut W) -> Result +where + R: Read, + W: Write, +{ + let read_buf = BufferedReaderSpec::buffer_size(reader); + let write_buf = BufferedWriterSpec::buffer_size(writer); + + if read_buf >= DEFAULT_BUF_SIZE && read_buf >= write_buf { + return BufferedReaderSpec::copy_to(reader, writer); + } + + BufferedWriterSpec::copy_from(writer, reader) +} + +/// Specialization of the read-write loop that reuses the internal +/// buffer of a BufReader. If there's no buffer then the writer side +/// should be used instead. +trait BufferedReaderSpec { + fn buffer_size(&self) -> usize; + + fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result; +} + +impl BufferedReaderSpec for T +where + Self: Read, + T: ?Sized, +{ + #[inline] + default fn buffer_size(&self) -> usize { + 0 + } + + default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result { + unreachable!("only called from specializations") + } +} + +impl BufferedReaderSpec for &[u8] { + fn buffer_size(&self) -> usize { + // prefer this specialization since the source "buffer" is all we'll ever need, + // even if it's small + usize::MAX + } + + fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { + let len = self.len(); + to.write_all(self)?; + *self = &self[len..]; + Ok(len as u64) + } +} + +#[cfg(not(no_global_oom_handling))] +impl BufferedReaderSpec for VecDeque { + fn buffer_size(&self) -> usize { + // prefer this specialization since the source "buffer" is all we'll ever need, + // even if it's small + usize::MAX + } + + fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { + let len = self.len(); + let (front, back) = self.as_slices(); + let bufs = &mut [IoSlice::new(front), IoSlice::new(back)]; + to.write_all_vectored(bufs)?; + self.clear(); + Ok(len as u64) + } +} + +impl BufferedReaderSpec for BufReader +where + Self: Read, + I: ?Sized, +{ + fn buffer_size(&self) -> usize { + self.capacity() + } + + fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { + let mut len = 0; + + loop { + // Hack: this relies on `impl Read for BufReader` always calling fill_buf + // if the buffer is empty, even for empty slices. + // It can't be called directly here since specialization prevents us + // from adding I: Read + match self.read(&mut []) { + Ok(_) => {} + Err(e) if e.is_interrupted() => continue, + Err(e) => return Err(e), + } + let buf = self.buffer(); + if self.buffer().len() == 0 { + return Ok(len); + } + + // In case the writer side is a BufWriter then its write_all + // implements an optimization that passes through large + // buffers to the underlying writer. That code path is #[cold] + // but we're still avoiding redundant memcopies when doing + // a copy between buffered inputs and outputs. + to.write_all(buf)?; + len += buf.len() as u64; + self.discard_buffer(); + } + } +} + +/// Specialization of the read-write loop that either uses a stack buffer +/// or reuses the internal buffer of a BufWriter +trait BufferedWriterSpec: Write { + fn buffer_size(&self) -> usize; + + fn copy_from(&mut self, reader: &mut R) -> Result; +} + +impl BufferedWriterSpec for W { + #[inline] + default fn buffer_size(&self) -> usize { + 0 + } + + default fn copy_from(&mut self, reader: &mut R) -> Result { + stack_buffer_copy(reader, self) + } +} + +impl BufferedWriterSpec for BufWriter { + fn buffer_size(&self) -> usize { + self.capacity() + } + + fn copy_from(&mut self, reader: &mut R) -> Result { + if self.capacity() < DEFAULT_BUF_SIZE { + return stack_buffer_copy(reader, self); + } + + let mut len = 0; + let mut init = false; + + loop { + let buf = self.buffer_mut(); + let mut read_buf: BorrowedBuf<'_, u8> = buf.spare_capacity_mut().into(); + + if init { + // SAFETY: `init` is only true after `reader` initializes + // `read_buf`. See the comment about `flush_buf` below. + unsafe { read_buf.set_init() }; + } + + if read_buf.capacity() >= DEFAULT_BUF_SIZE { + let mut cursor = read_buf.unfilled(); + match reader.read_buf(cursor.reborrow()) { + Ok(()) => { + let bytes_read = cursor.written(); + + if bytes_read == 0 { + return Ok(len); + } + + init = read_buf.is_init(); + len += bytes_read as u64; + + // SAFETY: BorrowedBuf guarantees all of its filled bytes are init + unsafe { buf.set_len(buf.len() + bytes_read) }; + + // Read again if the buffer still has enough capacity, as BufWriter itself would do + // This will occur if the reader returns short reads + } + Err(ref e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + } else { + // SAFETY: `flush_buf` will not de-initialize any elements of + // the spare capacity so we can remember `init` across this. + self.flush_buf()?; + } + } + } +} + +impl BufferedWriterSpec for Vec { + fn buffer_size(&self) -> usize { + cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len()) + } + + fn copy_from(&mut self, reader: &mut R) -> Result { + reader.read_to_end(self).map(|bytes| u64::try_from(bytes).expect("usize overflowed u64")) + } +} + +fn stack_buffer_copy( + reader: &mut R, + writer: &mut W, +) -> Result { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); DEFAULT_BUF_SIZE]; + let mut buf: BorrowedBuf<'_, u8> = buf.into(); + + let mut len = 0; + + loop { + match reader.read_buf(buf.unfilled()) { + Ok(()) => {} + Err(e) if e.is_interrupted() => continue, + Err(e) => return Err(e), + }; + + if buf.filled().is_empty() { + break; + } + + len += buf.filled().len() as u64; + writer.write_all(buf.filled())?; + buf.clear(); + } + + Ok(len) +} diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs index ff39cb145a929..57c113db530ec 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -1,6 +1,8 @@ //! Traits, helpers, and type definitions for core I/O functionality. mod buf_read; +mod buffered; +mod copy; mod cursor; mod error; mod impls; @@ -22,24 +24,28 @@ pub use core::io::{ }; #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub use core::io::{ - IoHandle, OsFunctions, SizeHint, WriteThroughCursor, chain, default_write_vectored, - slice_write, slice_write_all, slice_write_all_vectored, slice_write_vectored, - stream_len_default, take, +pub use core::io::{IoHandle, OsFunctions, default_write_vectored, stream_len_default}; +use core::io::{ + SizeHint, WriteThroughCursor, chain, slice_write, slice_write_all, slice_write_all_vectored, + slice_write_vectored, take, }; +use self::read::{append_to_string, default_read_buf_exact, default_read_exact}; +use self::util::{bytes, lines, split, uninlined_slow_read_byte}; #[unstable(feature = "alloc_io", issue = "154046")] pub use self::{ buf_read::BufRead, + buffered::{BufReader, BufWriter, IntoInnerError, LineWriter, WriterPanicked}, read::{Read, read_to_string}, util::{Bytes, Lines, Split}, }; #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub use self::{ + copy::generic_copy, read::{ - DEFAULT_BUF_SIZE, append_to_string, default_read_buf, default_read_buf_exact, - default_read_exact, default_read_to_end, default_read_to_string, default_read_vectored, + DEFAULT_BUF_SIZE, default_read_buf, default_read_to_end, default_read_to_string, + default_read_vectored, }, - util::{SpecReadByte, bytes, lines, split, uninlined_slow_read_byte}, + util::SpecReadByte, }; diff --git a/library/alloc/src/io/read.rs b/library/alloc/src/io/read.rs index c1356811cc58a..1b47c20b01962 100644 --- a/library/alloc/src/io/read.rs +++ b/library/alloc/src/io/read.rs @@ -795,9 +795,7 @@ pub const DEFAULT_BUF_SIZE: usize = cfg_select! { /// 2. We're passing a raw buffer to the function `f`, and it is expected that /// the function only *appends* bytes to the buffer. We'll get undefined /// behavior if existing bytes are overwritten to have non-UTF-8 data. -#[doc(hidden)] -#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub unsafe fn append_to_string(buf: &mut String, f: F) -> Result +pub(in crate::io) unsafe fn append_to_string(buf: &mut String, f: F) -> Result where F: FnOnce(&mut Vec) -> Result, { @@ -988,9 +986,10 @@ where read(buf) } -#[doc(hidden)] -#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub fn default_read_exact(this: &mut R, mut buf: &mut [u8]) -> Result<()> { +pub(in crate::io) fn default_read_exact( + this: &mut R, + mut buf: &mut [u8], +) -> Result<()> { while !buf.is_empty() { match this.read(buf) { Ok(0) => break, @@ -1015,9 +1014,7 @@ where Ok(()) } -#[doc(hidden)] -#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub fn default_read_buf_exact( +pub(in crate::io) fn default_read_buf_exact( this: &mut R, mut cursor: BorrowedCursor<'_, u8>, ) -> Result<()> { diff --git a/library/alloc/src/io/util.rs b/library/alloc/src/io/util.rs index 050e018e8568f..567a041be5b78 100644 --- a/library/alloc/src/io/util.rs +++ b/library/alloc/src/io/util.rs @@ -388,15 +388,11 @@ fn inlined_slow_read_byte(reader: &mut R) -> Option> { // Used by `BufReader::spec_read_byte`, for which the `inline(never)` is // important. #[inline(never)] -#[doc(hidden)] -#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub fn uninlined_slow_read_byte(reader: &mut R) -> Option> { +pub(in crate::io) fn uninlined_slow_read_byte(reader: &mut R) -> Option> { inlined_slow_read_byte(reader) } -#[doc(hidden)] -#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub const fn bytes(inner: R) -> Bytes { +pub(in crate::io) const fn bytes(inner: R) -> Bytes { Bytes { inner } } @@ -434,9 +430,7 @@ impl Iterator for Split { } } -#[doc(hidden)] -#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub const fn split(buf: B, delim: u8) -> Split { +pub(in crate::io) const fn split(buf: B, delim: u8) -> Split { Split { buf, delim } } @@ -475,8 +469,6 @@ impl Iterator for Lines { } } -#[doc(hidden)] -#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub const fn lines(buf: B) -> Lines { +pub(in crate::io) const fn lines(buf: B) -> Lines { Lines { buf } } diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index e36f2d92108d0..1d09ff7d8dc1c 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -1,189 +1,4 @@ //! Buffering wrappers for I/O traits -mod bufreader; -mod bufwriter; -mod linewriter; -mod linewritershim; - #[cfg(test)] mod tests; - -#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] -pub use bufwriter::WriterPanicked; -use linewritershim::LineWriterShim; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter}; -use crate::io::Error; -use crate::{error, fmt}; - -/// An error returned by [`BufWriter::into_inner`] which combines an error that -/// happened while writing out the buffer, and the buffered writer object -/// which may be used to recover from the condition. -/// -/// # Examples -/// -/// ```no_run -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// // do stuff with the stream -/// -/// // we want to get our `TcpStream` back, so let's try: -/// -/// let stream = match stream.into_inner() { -/// Ok(s) => s, -/// Err(e) => { -/// // Here, e is an IntoInnerError -/// panic!("An error occurred"); -/// } -/// }; -/// ``` -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoInnerError(W, Error); - -impl IntoInnerError { - /// Constructs a new IntoInnerError - fn new(writer: W, error: Error) -> Self { - Self(writer, error) - } - - /// Helper to construct a new IntoInnerError; intended to help with - /// adapters that wrap other adapters - fn new_wrapped(self, f: impl FnOnce(W) -> W2) -> IntoInnerError { - let Self(writer, error) = self; - IntoInnerError::new(f(writer), error) - } - - /// Returns the error which caused the call to [`BufWriter::into_inner()`] - /// to fail. - /// - /// This error was returned when attempting to write the internal buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's log the inner error. - /// // - /// // We'll just 'log' to stdout for this example. - /// println!("{}", e.error()); - /// - /// panic!("An unexpected error occurred."); - /// } - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn error(&self) -> &Error { - &self.1 - } - - /// Returns the buffered writer instance which generated the error. - /// - /// The returned object can be used for error recovery, such as - /// re-inspecting the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's re-examine the buffer: - /// let buffer = e.into_inner(); - /// - /// // do stuff to try to recover - /// - /// // afterwards, let's just return the stream - /// buffer.into_inner().unwrap() - /// } - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> W { - self.0 - } - - /// Consumes the [`IntoInnerError`] and returns the error which caused the call to - /// [`BufWriter::into_inner()`] to fail. Unlike `error`, this can be used to - /// obtain ownership of the underlying error. - /// - /// # Example - /// ``` - /// use std::io::{BufWriter, ErrorKind, Write}; - /// - /// let mut not_enough_space = [0u8; 10]; - /// let mut stream = BufWriter::new(not_enough_space.as_mut()); - /// write!(stream, "this cannot be actually written").unwrap(); - /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); - /// let err = into_inner_err.into_error(); - /// assert_eq!(err.kind(), ErrorKind::WriteZero); - /// ``` - #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")] - pub fn into_error(self) -> Error { - self.1 - } - - /// Consumes the [`IntoInnerError`] and returns the error which caused the call to - /// [`BufWriter::into_inner()`] to fail, and the underlying writer. - /// - /// This can be used to simply obtain ownership of the underlying error; it can also be used for - /// advanced error recovery. - /// - /// # Example - /// ``` - /// use std::io::{BufWriter, ErrorKind, Write}; - /// - /// let mut not_enough_space = [0u8; 10]; - /// let mut stream = BufWriter::new(not_enough_space.as_mut()); - /// write!(stream, "this cannot be actually written").unwrap(); - /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); - /// let (err, recovered_writer) = into_inner_err.into_parts(); - /// assert_eq!(err.kind(), ErrorKind::WriteZero); - /// assert_eq!(recovered_writer.buffer(), b"t be actually written"); - /// ``` - #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")] - pub fn into_parts(self) -> (Error, W) { - (self.1, self.0) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From> for Error { - fn from(iie: IntoInnerError) -> Error { - iie.1 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for IntoInnerError {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for IntoInnerError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.error().fmt(f) - } -} diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 43c6f71357e61..45411ef9ea1b7 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,9 +1,4 @@ -use super::{BorrowedBuf, BufReader, BufWriter, DEFAULT_BUF_SIZE, Read, Result, Write}; -use crate::alloc::Allocator; -use crate::cmp; -use crate::collections::VecDeque; -use crate::io::IoSlice; -use crate::mem::MaybeUninit; +use crate::io::{Read, Result, Write, generic_copy}; use crate::sys::io::{CopyState, kernel_copy}; #[cfg(test)] @@ -71,226 +66,3 @@ where } } } - -/// The userspace read-write-loop implementation of `io::copy` that is used when -/// OS-specific specializations for copy offloading are not available or not applicable. -fn generic_copy(reader: &mut R, writer: &mut W) -> Result -where - R: Read, - W: Write, -{ - let read_buf = BufferedReaderSpec::buffer_size(reader); - let write_buf = BufferedWriterSpec::buffer_size(writer); - - if read_buf >= DEFAULT_BUF_SIZE && read_buf >= write_buf { - return BufferedReaderSpec::copy_to(reader, writer); - } - - BufferedWriterSpec::copy_from(writer, reader) -} - -/// Specialization of the read-write loop that reuses the internal -/// buffer of a BufReader. If there's no buffer then the writer side -/// should be used instead. -trait BufferedReaderSpec { - fn buffer_size(&self) -> usize; - - fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result; -} - -impl BufferedReaderSpec for T -where - Self: Read, - T: ?Sized, -{ - #[inline] - default fn buffer_size(&self) -> usize { - 0 - } - - default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result { - unreachable!("only called from specializations") - } -} - -impl BufferedReaderSpec for &[u8] { - fn buffer_size(&self) -> usize { - // prefer this specialization since the source "buffer" is all we'll ever need, - // even if it's small - usize::MAX - } - - fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { - let len = self.len(); - to.write_all(self)?; - *self = &self[len..]; - Ok(len as u64) - } -} - -impl BufferedReaderSpec for VecDeque { - fn buffer_size(&self) -> usize { - // prefer this specialization since the source "buffer" is all we'll ever need, - // even if it's small - usize::MAX - } - - fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { - let len = self.len(); - let (front, back) = self.as_slices(); - let bufs = &mut [IoSlice::new(front), IoSlice::new(back)]; - to.write_all_vectored(bufs)?; - self.clear(); - Ok(len as u64) - } -} - -impl BufferedReaderSpec for BufReader -where - Self: Read, - I: ?Sized, -{ - fn buffer_size(&self) -> usize { - self.capacity() - } - - fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { - let mut len = 0; - - loop { - // Hack: this relies on `impl Read for BufReader` always calling fill_buf - // if the buffer is empty, even for empty slices. - // It can't be called directly here since specialization prevents us - // from adding I: Read - match self.read(&mut []) { - Ok(_) => {} - Err(e) if e.is_interrupted() => continue, - Err(e) => return Err(e), - } - let buf = self.buffer(); - if self.buffer().len() == 0 { - return Ok(len); - } - - // In case the writer side is a BufWriter then its write_all - // implements an optimization that passes through large - // buffers to the underlying writer. That code path is #[cold] - // but we're still avoiding redundant memcopies when doing - // a copy between buffered inputs and outputs. - to.write_all(buf)?; - len += buf.len() as u64; - self.discard_buffer(); - } - } -} - -/// Specialization of the read-write loop that either uses a stack buffer -/// or reuses the internal buffer of a BufWriter -trait BufferedWriterSpec: Write { - fn buffer_size(&self) -> usize; - - fn copy_from(&mut self, reader: &mut R) -> Result; -} - -impl BufferedWriterSpec for W { - #[inline] - default fn buffer_size(&self) -> usize { - 0 - } - - default fn copy_from(&mut self, reader: &mut R) -> Result { - stack_buffer_copy(reader, self) - } -} - -impl BufferedWriterSpec for BufWriter { - fn buffer_size(&self) -> usize { - self.capacity() - } - - fn copy_from(&mut self, reader: &mut R) -> Result { - if self.capacity() < DEFAULT_BUF_SIZE { - return stack_buffer_copy(reader, self); - } - - let mut len = 0; - let mut init = false; - - loop { - let buf = self.buffer_mut(); - let mut read_buf: BorrowedBuf<'_, u8> = buf.spare_capacity_mut().into(); - - if init { - // SAFETY: `init` is only true after `reader` initializes - // `read_buf`. See the comment about `flush_buf` below. - unsafe { read_buf.set_init() }; - } - - if read_buf.capacity() >= DEFAULT_BUF_SIZE { - let mut cursor = read_buf.unfilled(); - match reader.read_buf(cursor.reborrow()) { - Ok(()) => { - let bytes_read = cursor.written(); - - if bytes_read == 0 { - return Ok(len); - } - - init = read_buf.is_init(); - len += bytes_read as u64; - - // SAFETY: BorrowedBuf guarantees all of its filled bytes are init - unsafe { buf.set_len(buf.len() + bytes_read) }; - - // Read again if the buffer still has enough capacity, as BufWriter itself would do - // This will occur if the reader returns short reads - } - Err(ref e) if e.is_interrupted() => {} - Err(e) => return Err(e), - } - } else { - // SAFETY: `flush_buf` will not de-initialize any elements of - // the spare capacity so we can remember `init` across this. - self.flush_buf()?; - } - } - } -} - -impl BufferedWriterSpec for Vec { - fn buffer_size(&self) -> usize { - cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len()) - } - - fn copy_from(&mut self, reader: &mut R) -> Result { - reader.read_to_end(self).map(|bytes| u64::try_from(bytes).expect("usize overflowed u64")) - } -} - -fn stack_buffer_copy( - reader: &mut R, - writer: &mut W, -) -> Result { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); DEFAULT_BUF_SIZE]; - let mut buf: BorrowedBuf<'_, u8> = buf.into(); - - let mut len = 0; - - loop { - match reader.read_buf(buf.unfilled()) { - Ok(()) => {} - Err(e) if e.is_interrupted() => continue, - Err(e) => return Err(e), - }; - - if buf.filled().is_empty() { - break; - } - - len += buf.filled().len() as u64; - writer.write_all(buf.filled())?; - buf.clear(); - } - - Ok(len) -} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index dbc92d7b45d7c..a9a61a50ec589 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -302,6 +302,8 @@ pub use alloc_crate::io::RawOsError; #[doc(hidden)] #[unstable(feature = "io_const_error_internals", issue = "none")] pub use alloc_crate::io::SimpleMessage; +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] +pub use alloc_crate::io::WriterPanicked; #[unstable(feature = "io_const_error", issue = "133448")] pub use alloc_crate::io::const_error; #[stable(feature = "io_read_to_string", since = "1.65.0")] @@ -310,43 +312,40 @@ pub use alloc_crate::io::read_to_string; pub use alloc_crate::io::{BorrowedBuf, BorrowedCursor}; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::io::{ - BufRead, Bytes, Chain, Cursor, Empty, Error, ErrorKind, Lines, Read, Repeat, Result, Seek, - SeekFrom, Sink, Split, Take, Write, empty, repeat, sink, + BufRead, BufReader, BufWriter, Bytes, Chain, Cursor, Empty, Error, ErrorKind, IntoInnerError, + LineWriter, Lines, Read, Repeat, Result, Seek, SeekFrom, Sink, Split, Take, Write, empty, + repeat, sink, }; #[allow(unused_imports, reason = "only used by certain platforms")] pub(crate) use alloc_crate::io::{ DEFAULT_BUF_SIZE, default_read_buf, default_read_vectored, default_write_vectored, }; pub(crate) use alloc_crate::io::{ - IoHandle, SpecReadByte, append_to_string, default_read_buf_exact, default_read_exact, - default_read_to_end, default_read_to_string, stream_len_default, uninlined_slow_read_byte, + IoHandle, SpecReadByte, default_read_to_end, default_read_to_string, stream_len_default, }; #[stable(feature = "iovec", since = "1.36.0")] pub use alloc_crate::io::{IoSlice, IoSliceMut}; -use alloc_crate::io::{OsFunctions, SizeHint}; +use alloc_crate::io::{OsFunctions, generic_copy}; -#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] -pub use self::buffered::WriterPanicked; #[stable(feature = "anonymous_pipe", since = "1.87.0")] pub use self::pipe::{PipeReader, PipeWriter, pipe}; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; -pub(crate) use self::stdio::attempt_print_to_stderr; #[unstable(feature = "print_internals", issue = "none")] #[doc(hidden)] pub use self::stdio::{_eprint, _print}; +pub(crate) use self::stdio::{attempt_print_to_stderr, cleanup}; #[unstable(feature = "internal_output_capture", issue = "none")] #[doc(no_inline, hidden)] pub use self::stdio::{set_output_capture, try_set_output_capture}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::{ - buffered::{BufReader, BufWriter, IntoInnerError, LineWriter}, copy::copy, stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout}, }; mod buffered; -pub(crate) mod copy; +mod copy; mod cursor; mod error; mod impls; @@ -354,5 +353,3 @@ mod pipe; pub mod prelude; mod stdio; mod util; - -pub(crate) use stdio::cleanup; diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr index eadf512a63b49..5ba7fcb2479bb 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -8,7 +8,7 @@ LL | let fp = BufWriter::new(fp); | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` note: required by a bound in `BufWriter::::new` - --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL + --> $SRC_DIR/alloc/src/io/buffered/bufwriter.rs:LL:COL error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied --> $DIR/mut-borrow-needed-by-trait.rs:17:14 @@ -18,7 +18,7 @@ LL | let fp = BufWriter::new(fp); | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` note: required by a bound in `BufWriter` - --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL + --> $SRC_DIR/alloc/src/io/buffered/bufwriter.rs:LL:COL error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied --> $DIR/mut-borrow-needed-by-trait.rs:21:14 diff --git a/tests/ui/suggestions/suggest-change-mut.stderr b/tests/ui/suggestions/suggest-change-mut.stderr index c47ae433ab896..fc664c92ceee2 100644 --- a/tests/ui/suggestions/suggest-change-mut.stderr +++ b/tests/ui/suggestions/suggest-change-mut.stderr @@ -7,7 +7,7 @@ LL | let mut stream_reader = BufReader::new(&stream); | required by a bound introduced by this call | note: required by a bound in `BufReader::::new` - --> $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL + --> $SRC_DIR/alloc/src/io/buffered/bufreader.rs:LL:COL help: consider removing the leading `&`-reference | LL - let mut stream_reader = BufReader::new(&stream);