diff --git a/library/std/src/io/buffered/bufreader.rs b/library/alloc/src/io/buffered/bufreader.rs similarity index 93% rename from library/std/src/io/buffered/bufreader.rs rename to library/alloc/src/io/buffered/bufreader.rs index 8d122c8e76e5f..e8b3302e29b98 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/alloc/src/io/buffered/bufreader.rs @@ -7,6 +7,8 @@ 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,17 +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 { - Buffer::try_with_capacity(DEFAULT_BUF_SIZE) - } - - pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self { - Self { inner, buf } + /// Attempts to allocate an internal buffer, _then_ calls the provided function + /// to retrieve the inner reader `R`. + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + #[inline] + pub fn try_new_with(f: impl FnOnce() -> io::Result) -> io::Result { + let buf = Buffer::try_with_capacity(DEFAULT_BUF_SIZE)?; + let inner = f()?; + Ok(Self { inner, buf }) } /// Creates a new `BufReader` with the specified buffer capacity. @@ -99,6 +106,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 +288,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 +424,16 @@ 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 => { + buf.try_extend_from_slice_of_bytes(inner_buf)?; + } + _ => { + buf.extend_from_slice(inner_buf); + } + } + let nread = inner_buf.len(); self.discard_buffer(); Ok(nread + self.inner.read_to_end(buf)?) @@ -445,7 +465,16 @@ 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 => { + buf.try_push_str(string)?; + } + _ => { + buf.push_str(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 83% rename from library/std/src/io/buffered/bufreader/buffer.rs rename to library/alloc/src/io/buffered/bufreader/buffer.rs index f2efcc5ab8601..316889d93f576 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/alloc/src/io/buffered/bufreader/buffer.rs @@ -9,11 +9,13 @@ //! 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; -pub struct Buffer { +pub(super) struct Buffer { // The buffer. buf: Box<[MaybeUninit]>, // The current seek offset into `buf`, must always be <= `filled`. @@ -29,14 +31,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 +49,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 +104,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 +126,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..4847c1605ac79 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,21 +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> { - Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| { + /// Attempts to allocate an internal buffer, _then_ calls the provided function + /// to retrieve the inner writer `W`. + #[doc(hidden)] + #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] + #[inline] + pub fn try_new_with(f: impl FnOnce() -> io::Result) -> io::Result { + let buf = 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 { - Self { inner, buf, panicked: false } + })?; + let inner = f()?; + Ok(Self { inner, buf, panicked: false }) } /// Creates a new `BufWriter` with at least the specified buffer capacity. @@ -115,8 +123,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 +146,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 +203,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 +300,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 +357,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/mod.rs b/library/alloc/src/io/mod.rs index ff39cb145a929..ef09d13cc6247 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -1,6 +1,7 @@ //! Traits, helpers, and type definitions for core I/O functionality. mod buf_read; +mod buffered; mod cursor; mod error; mod impls; @@ -22,15 +23,18 @@ 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}, }; @@ -38,8 +42,8 @@ pub use self::{ #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub use self::{ 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..c0123c860b453 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(super) unsafe fn append_to_string(buf: &mut String, f: F) -> Result where F: FnOnce(&mut Vec) -> Result, { @@ -988,9 +986,7 @@ 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(super) 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 +1011,7 @@ where Ok(()) } -#[doc(hidden)] -#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub fn default_read_buf_exact( +pub(super) 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..9bf5a56dd7157 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(super) 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(super) 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(super) 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(super) const fn lines(buf: B) -> Lines { Lines { buf } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 3574855e04dc9..388bf4a55e11f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -604,9 +604,7 @@ impl File { #[unstable(feature = "file_buffered", issue = "130804")] pub fn open_buffered>(path: P) -> io::Result> { // Allocate the buffer *first* so we don't affect the filesystem otherwise. - let buffer = io::BufReader::::try_new_buffer()?; - let file = File::open(path)?; - Ok(io::BufReader::with_buffer(file, buffer)) + io::BufReader::try_new_with(|| File::open(path)) } /// Opens a file in write-only mode. @@ -672,9 +670,7 @@ impl File { #[unstable(feature = "file_buffered", issue = "130804")] pub fn create_buffered>(path: P) -> io::Result> { // Allocate the buffer *first* so we don't affect the filesystem otherwise. - let buffer = io::BufWriter::::try_new_buffer()?; - let file = File::create(path)?; - Ok(io::BufWriter::with_buffer(file, buffer)) + io::BufWriter::try_new_with(|| File::create(path)) } /// Creates a new file in read-write mode; error if the file exists. 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/mod.rs b/library/std/src/io/mod.rs index dbc92d7b45d7c..572f0fb3e4611 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -297,11 +297,14 @@ #[cfg(test)] mod tests; +use alloc_crate::io::OsFunctions; #[unstable(feature = "raw_os_error_ty", issue = "107792")] 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,23 +313,20 @@ 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}; -#[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")] @@ -340,7 +340,6 @@ pub use self::stdio::{_eprint, _print}; 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}, }; 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);