diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index b2f4277458f1c..19f7426e4ee68 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -9,9 +9,10 @@ use core::{fmt, mem, ops, ptr, slice}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; +#[cfg(not(no_rc))] use crate::rc::Rc; use crate::string::String; -#[cfg(target_has_atomic = "ptr")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] use crate::sync::Arc; use crate::vec::Vec; @@ -898,7 +899,7 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> { } } -#[cfg(target_has_atomic = "ptr")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { /// Converts a [`CString`] into an [Arc]<[CStr]> by moving the [`CString`] @@ -910,7 +911,7 @@ impl From for Arc { } } -#[cfg(target_has_atomic = "ptr")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&CStr> for Arc { /// Converts a `&CStr` into a `Arc`, @@ -922,7 +923,7 @@ impl From<&CStr> for Arc { } } -#[cfg(target_has_atomic = "ptr")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] #[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut CStr> for Arc { /// Converts a `&mut CStr` into a `Arc`, @@ -933,6 +934,7 @@ impl From<&mut CStr> for Arc { } } +#[cfg(not(no_rc))] #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { /// Converts a [`CString`] into an [Rc]<[CStr]> by moving the [`CString`] @@ -944,6 +946,7 @@ impl From for Rc { } } +#[cfg(not(no_rc))] #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&CStr> for Rc { /// Converts a `&CStr` into a `Rc`, @@ -955,6 +958,7 @@ impl From<&CStr> for Rc { } } +#[cfg(not(no_rc))] #[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut CStr> for Rc { /// Converts a `&mut CStr` into a `Rc`, @@ -965,6 +969,7 @@ impl From<&mut CStr> for Rc { } } +#[cfg(not(no_rc))] #[cfg(not(no_global_oom_handling))] #[stable(feature = "more_rc_default_impls", since = "1.80.0")] impl Default for Rc { diff --git a/library/std/src/io/buffered/bufreader.rs b/library/alloc/src/io/buffered/bufreader.rs similarity index 98% rename from library/std/src/io/buffered/bufreader.rs rename to library/alloc/src/io/buffered/bufreader.rs index 40441dc057d0d..eb6442d197b38 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. /// @@ -74,11 +76,15 @@ impl BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } - pub(crate) fn try_new_buffer() -> io::Result { + #[unstable(feature = "io_internals", issue = "none")] + #[doc(hidden)] + pub fn try_new_buffer() -> io::Result { Buffer::try_with_capacity(DEFAULT_BUF_SIZE) } - pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self { + #[unstable(feature = "io_internals", issue = "none")] + #[doc(hidden)] + pub fn with_buffer(inner: R, buf: Buffer) -> Self { Self { inner, buf } } @@ -285,9 +291,9 @@ impl BufReader { } // This is only used by a test which asserts that the initialization-tracking is correct. -#[cfg(test)] impl BufReader { - #[allow(missing_docs)] + #[unstable(feature = "io_internals", issue = "none")] + #[doc(hidden)] pub fn initialized(&self) -> usize { self.buf.initialized() } diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/alloc/src/io/buffered/bufreader/buffer.rs similarity index 98% rename from library/std/src/io/buffered/bufreader/buffer.rs rename to library/alloc/src/io/buffered/bufreader/buffer.rs index ad8608bf61908..892097357cddd 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/alloc/src/io/buffered/bufreader/buffer.rs @@ -9,10 +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; +#[derive(Debug)] pub struct Buffer { // The buffer. buf: Box<[MaybeUninit]>, @@ -69,7 +72,7 @@ impl Buffer { } // This is only used by a test which asserts that the initialization-tracking is correct. - #[cfg(test)] + #[inline] pub fn initialized(&self) -> usize { self.initialized } diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/alloc/src/io/buffered/bufwriter.rs similarity index 98% rename from library/std/src/io/buffered/bufwriter.rs rename to library/alloc/src/io/buffered/bufwriter.rs index d569fed24c561..23178a5cdc507 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. /// @@ -94,13 +96,17 @@ impl BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - pub(crate) fn try_new_buffer() -> io::Result> { + #[unstable(feature = "io_internals", issue = "none")] + #[doc(hidden)] + 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 { + #[unstable(feature = "io_internals", issue = "none")] + #[doc(hidden)] + pub fn with_buffer(inner: W, buf: Vec) -> Self { Self { inner, buf, panicked: false } } diff --git a/library/std/src/io/buffered/linewriter.rs b/library/alloc/src/io/buffered/linewriter.rs similarity index 100% rename from library/std/src/io/buffered/linewriter.rs rename to library/alloc/src/io/buffered/linewriter.rs 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 967e24812b9ff..eb11ff820fd40 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/std/src/io/buffered/mod.rs b/library/alloc/src/io/buffered/mod.rs similarity index 99% rename from library/std/src/io/buffered/mod.rs rename to library/alloc/src/io/buffered/mod.rs index e36f2d92108d0..b16f8a60671b3 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/alloc/src/io/buffered/mod.rs @@ -8,6 +8,8 @@ mod linewritershim; #[cfg(test)] mod tests; +use core::{error, fmt}; + #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub use bufwriter::WriterPanicked; use linewritershim::LineWriterShim; @@ -15,7 +17,6 @@ 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 diff --git a/library/alloc/src/io/copy.rs b/library/alloc/src/io/copy.rs new file mode 100644 index 0000000000000..3ff8a9cd78227 --- /dev/null +++ b/library/alloc/src/io/copy.rs @@ -0,0 +1,282 @@ +use core::cmp; +use core::mem::MaybeUninit; + +use super::{BorrowedBuf, BufReader, BufWriter, DEFAULT_BUF_SIZE, Read, Result, Write}; +use crate::alloc::Allocator; +use crate::collections::VecDeque; +use crate::io::IoSlice; + +#[cfg(test)] +mod tests; + +/// Copies the entire contents of a reader into a writer. +/// +/// This function will continuously read data from `reader` and then +/// write it into `writer` in a streaming fashion until `reader` +/// returns EOF. +/// +/// On success, the total number of bytes that were copied from +/// `reader` to `writer` is returned. +/// +/// If you want to copy the contents of one file to another and you’re +/// working with filesystem paths, see the [`fs::copy`] function. +/// +/// [`fs::copy`]: crate::fs::copy +/// +/// # Errors +/// +/// This function will return an error immediately if any call to [`read`] or +/// [`write`] returns an error. All instances of [`ErrorKind::Interrupted`] are +/// handled by this function and the underlying operation is retried. +/// +/// [`read`]: Read::read +/// [`write`]: Write::write +/// [`ErrorKind::Interrupted`]: crate::io::ErrorKind::Interrupted +/// +/// # Examples +/// +/// ``` +/// use std::io; +/// +/// fn main() -> io::Result<()> { +/// let mut reader: &[u8] = b"hello"; +/// let mut writer: Vec = vec![]; +/// +/// io::copy(&mut reader, &mut writer)?; +/// +/// assert_eq!(&b"hello"[..], &writer[..]); +/// Ok(()) +/// } +/// ``` +/// +/// # Platform-specific behavior +/// +/// On Linux (including Android), this function uses `copy_file_range(2)`, +/// `sendfile(2)` or `splice(2)` syscalls to move data directly between file +/// descriptors if possible. +/// +/// Note that platform-specific behavior [may change in the future][changes]. +/// +/// [changes]: crate::io#platform-specific-behavior +#[stable(feature = "rust1", since = "1.0.0")] +pub fn 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 = 0; + + loop { + let buf = self.buffer_mut(); + let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); + + unsafe { + // SAFETY: init is either 0 or the init_len from the previous iteration. + read_buf.set_init(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.init_len() - bytes_read; + 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 { + // All the bytes that were already in the buffer are initialized, + // treat them as such when the buffer is flushed. + init += buf.len(); + + self.flush_buf()?; + } + } + } +} + +impl BufferedWriterSpec for crate::vec::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<'_> = 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/cursor.rs b/library/alloc/src/io/cursor.rs similarity index 99% rename from library/std/src/io/cursor.rs rename to library/alloc/src/io/cursor.rs index d7131e2fe92fd..ccdc71bb24410 100644 --- a/library/std/src/io/cursor.rs +++ b/library/alloc/src/io/cursor.rs @@ -1,10 +1,14 @@ #[cfg(test)] mod tests; +use core::cmp; + use crate::alloc::Allocator; -use crate::cmp; +use crate::boxed::Box; use crate::io::prelude::*; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; +use crate::string::String; +use crate::vec::Vec; /// A `Cursor` wraps an in-memory buffer and provides it with a /// [`Seek`] implementation. diff --git a/library/alloc/src/io/error.rs b/library/alloc/src/io/error.rs new file mode 100644 index 0000000000000..9ad73100c23cc --- /dev/null +++ b/library/alloc/src/io/error.rs @@ -0,0 +1,1090 @@ +use core::{error, fmt, result}; + +use crate::boxed::Box; + +// On 64-bit platforms, `io::Error` may use a bit-packed representation to +// reduce size. However, this representation assumes that error codes are +// always 32-bit wide. +// +// This assumption is invalid on 64-bit UEFI, where error codes are 64-bit. +// Therefore, the packed representation is explicitly disabled for UEFI +// targets, and the unpacked representation must be used instead. + +cfg_select! { + all(target_pointer_width = "64", not(target_os = "uefi")) => { + use repr_bitpacked::Repr; + mod repr_bitpacked; + } + _ => { + mod repr_unpacked; + use repr_unpacked::Repr; + } +} + +#[cfg(target_has_atomic = "ptr")] +pub(super) mod os { + //! OS-dependent functions + //! + //! `Error` needs OS functionalities to work interpret raw OS errors, but + //! we can't link to anythink here in `alloc`. Therefore, we restrict + //! creation of `Error` from raw OS errors in `std`, and require providing + //! a vtable of operations when creating one. + + // FIXME: replace this with externally implementable items once they are more stable + + use core::sync::atomic; + + use super::{ErrorKind, RawOsError}; + use crate::string::String; + + #[doc(hidden)] + #[derive(Debug)] + pub struct OsFunctions { + pub error_string: fn(_: RawOsError) -> String, + pub decode_error_kind: fn(_: RawOsError) -> ErrorKind, + pub is_interrupted: fn(_: RawOsError) -> bool, + } + + /// These default functions are not reachable, but have them just to be safe. + const DEFAULT_FUNCTIONS: &'static OsFunctions = &OsFunctions { + error_string: |_| String::new(), + decode_error_kind: |_| ErrorKind::Uncategorized, + is_interrupted: |_| false, + }; + static OS_FUNCTIONS: atomic::AtomicPtr = + atomic::AtomicPtr::new(DEFAULT_FUNCTIONS as *const _ as *mut _); + + #[inline] + pub(super) fn set_functions(f: &'static OsFunctions) { + OS_FUNCTIONS.store(f as *const _ as *mut _, atomic::Ordering::Relaxed); + } + + #[inline] + pub(super) fn error_string(errno: RawOsError) -> String { + let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) }; + (f.error_string)(errno) + } + + #[inline] + pub(super) fn decode_error_kind(errno: RawOsError) -> ErrorKind { + let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) }; + (f.decode_error_kind)(errno) + } + + #[inline] + pub(super) fn is_interrupted(errno: RawOsError) -> bool { + let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) }; + (f.is_interrupted)(errno) + } +} + +// Disable these on target without atomics, they don't support `std` anyway +#[cfg(not(target_has_atomic = "ptr"))] +pub(super) mod os { + use super::{ErrorKind, RawOsError}; + use crate::string::String; + + #[inline] + pub(super) fn error_string(_: RawOsError) -> String { + String::new() + } + #[inline] + pub(super) fn decode_error_kind(_: RawOsError) -> ErrorKind { + ErrorKind::Uncategorized + } + #[inline] + pub(super) fn is_interrupted(_: RawOsError) -> bool { + false + } +} + +/// A specialized [`Result`] type for I/O operations. +/// +/// This type is broadly used across [`std::io`] for any operation which may +/// produce an error. +/// +/// This type alias is generally used to avoid writing out [`io::Error`] directly and +/// is otherwise a direct mapping to [`Result`]. +/// +/// While usual Rust style is to import types directly, aliases of [`Result`] +/// often are not, to make it easier to distinguish between them. [`Result`] is +/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias +/// will generally use `io::Result` instead of shadowing the [prelude]'s import +/// of [`std::result::Result`][`Result`]. +/// +/// [`std::io`]: crate::io +/// [`io::Error`]: Error +/// [`Result`]: core::result::Result +/// [prelude]: crate::prelude +/// +/// # Examples +/// +/// A convenience function that bubbles an `io::Result` to its caller: +/// +/// ``` +/// use std::io; +/// +/// fn get_string() -> io::Result { +/// let mut buffer = String::new(); +/// +/// io::stdin().read_line(&mut buffer)?; +/// +/// Ok(buffer) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(search_unbox)] +pub type Result = result::Result; + +/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and +/// associated traits. +/// +/// Errors mostly originate from the underlying OS, but custom instances of +/// `Error` can be created with crafted error messages and a particular value of +/// [`ErrorKind`]. +/// +/// [`Read`]: crate::io::Read +/// [`Write`]: crate::io::Write +/// [`Seek`]: crate::io::Seek +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_has_incoherent_inherent_impls] +pub struct Error { + repr: Repr, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.repr, f) + } +} + +/// Common errors constants for use in std +#[doc(hidden)] +#[unstable(feature = "io_error_internals", issue = "none")] +impl Error { + pub const INVALID_UTF8: Self = + const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); + + pub const READ_EXACT_EOF: Self = + const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); + + pub const UNKNOWN_THREAD_COUNT: Self = const_error!( + ErrorKind::NotFound, + "the number of hardware threads is not known for the target platform", + ); + + pub const UNSUPPORTED_PLATFORM: Self = + const_error!(ErrorKind::Unsupported, "operation not supported on this platform"); + + pub const WRITE_ALL_EOF: Self = + const_error!(ErrorKind::WriteZero, "failed to write whole buffer"); + + pub const ZERO_TIMEOUT: Self = + const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); + + pub const NO_ADDRESSES: Self = + const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses"); +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From for Error { + /// Converts a [`crate::ffi::NulError`] into a [`Error`]. + fn from(_: crate::ffi::NulError) -> Error { + const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") + } +} + +#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")] +impl From for Error { + /// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`]. + /// + /// `TryReserveError` won't be available as the error `source()`, + /// but this may change in the future. + fn from(_: crate::collections::TryReserveError) -> Error { + // ErrorData::Custom allocates, which isn't great for handling OOM errors. + ErrorKind::OutOfMemory.into() + } +} + +// Only derive debug in tests, to make sure it +// doesn't accidentally get printed. +#[cfg_attr(test, derive(Debug))] +enum ErrorData { + Os(RawOsError), + Simple(ErrorKind), + SimpleMessage(&'static SimpleMessage), + Custom(C), +} + +/// The type of raw OS error codes returned by [`Error::raw_os_error`]. +/// +/// This is an [`i32`] on all currently supported platforms, but platforms +/// added in the future (such as UEFI) may use a different primitive type like +/// [`usize`]. Use `as`or [`into`] conversions where applicable to ensure maximum +/// portability. +/// +/// [`into`]: Into::into +#[allow(unreachable_pub)] +pub type RawOsError = cfg_select! { + target_os = "uefi" => usize, + _ => i32, +}; + +// `#[repr(align(4))]` is probably redundant, it should have that value or +// higher already. We include it just because repr_bitpacked.rs's encoding +// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the +// alignment required by the struct, only increase it). +// +// If we add more variants to ErrorData, this can be increased to 8, but it +// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or +// whatever cfg we're using to enable the `repr_bitpacked` code, since only the +// that version needs the alignment, and 8 is higher than the alignment we'll +// have on 32 bit platforms. +// +// (For the sake of being explicit: the alignment requirement here only matters +// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't +// matter at all) +#[doc(hidden)] +#[unstable(feature = "io_const_error_internals", issue = "none")] +#[repr(align(4))] +#[derive(Debug)] +pub struct SimpleMessage { + pub kind: ErrorKind, + pub message: &'static str, +} + +/// Creates a new I/O error from a known kind of error and a string literal. +/// +/// Contrary to [`Error::new`], this macro does not allocate and can be used in +/// `const` contexts. +/// +/// # Example +/// ``` +/// #![feature(io_const_error)] +/// use std::io::{const_error, Error, ErrorKind}; +/// +/// const FAIL: Error = const_error!(ErrorKind::Unsupported, "tried something that never works"); +/// +/// fn not_here() -> Result<(), Error> { +/// Err(FAIL) +/// } +/// ``` +#[rustc_macro_transparency = "semiopaque"] +#[unstable(feature = "io_const_error", issue = "133448")] +#[allow_internal_unstable(alloc_io, hint_must_use, io_const_error_internals, liballoc_internals)] +pub macro const_error($kind:expr, $message:expr $(,)?) { + $crate::__export::must_use($crate::io::Error::from_static_message( + const { &$crate::io::SimpleMessage { kind: $kind, message: $message } }, + )) +} + +// As with `SimpleMessage`: `#[repr(align(4))]` here is just because +// repr_bitpacked's encoding requires it. In practice it almost certainly be +// already be this high or higher. +#[derive(Debug)] +#[repr(align(4))] +struct Custom { + kind: ErrorKind, + error: Box, +} + +/// A list specifying general categories of I/O error. +/// +/// This list is intended to grow over time and it is not recommended to +/// exhaustively match against it. +/// +/// It is used with the [`io::Error`] type. +/// +/// [`io::Error`]: Error +/// +/// # Handling errors and matching on `ErrorKind` +/// +/// In application code, use `match` for the `ErrorKind` values you are +/// expecting; use `_` to match "all other errors". +/// +/// In comprehensive and thorough tests that want to verify that a test doesn't +/// return any known incorrect error kind, you may want to cut-and-paste the +/// current full list of errors from here into your test code, and then match +/// `_` as the correct case. This seems counterintuitive, but it will make your +/// tests more robust. In particular, if you want to verify that your code does +/// produce an unrecognized error kind, the robust solution is to check for all +/// the recognized error kinds and fail in those cases. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "io_errorkind")] +#[allow(deprecated)] +#[non_exhaustive] +pub enum ErrorKind { + /// An entity was not found, often a file. + #[stable(feature = "rust1", since = "1.0.0")] + NotFound, + /// The operation lacked the necessary privileges to complete. + #[stable(feature = "rust1", since = "1.0.0")] + PermissionDenied, + /// The connection was refused by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionRefused, + /// The connection was reset by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionReset, + /// The remote host is not reachable. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + HostUnreachable, + /// The network containing the remote host is not reachable. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + NetworkUnreachable, + /// The connection was aborted (terminated) by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionAborted, + /// The network operation failed because it was not connected yet. + #[stable(feature = "rust1", since = "1.0.0")] + NotConnected, + /// A socket address could not be bound because the address is already in + /// use elsewhere. + #[stable(feature = "rust1", since = "1.0.0")] + AddrInUse, + /// A nonexistent interface was requested or the requested address was not + /// local. + #[stable(feature = "rust1", since = "1.0.0")] + AddrNotAvailable, + /// The system's networking is down. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + NetworkDown, + /// The operation failed because a pipe was closed. + #[stable(feature = "rust1", since = "1.0.0")] + BrokenPipe, + /// An entity already exists, often a file. + #[stable(feature = "rust1", since = "1.0.0")] + AlreadyExists, + /// The operation needs to block to complete, but the blocking operation was + /// requested to not occur. + #[stable(feature = "rust1", since = "1.0.0")] + WouldBlock, + /// A filesystem object is, unexpectedly, not a directory. + /// + /// For example, a filesystem path was specified where one of the intermediate directory + /// components was, in fact, a plain file. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + NotADirectory, + /// The filesystem object is, unexpectedly, a directory. + /// + /// A directory was specified when a non-directory was expected. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + IsADirectory, + /// A non-empty directory was specified where an empty directory was expected. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + DirectoryNotEmpty, + /// The filesystem or storage medium is read-only, but a write operation was attempted. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + ReadOnlyFilesystem, + /// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links. + /// + /// There was a loop (or excessively long chain) resolving a filesystem object + /// or file IO object. + /// + /// On Unix this is usually the result of a symbolic link loop; or, of exceeding the + /// system-specific limit on the depth of symlink traversal. + #[unstable(feature = "io_error_more", issue = "86442")] + FilesystemLoop, + /// Stale network file handle. + /// + /// With some network filesystems, notably NFS, an open file (or directory) can be invalidated + /// by problems with the network or server. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + StaleNetworkFileHandle, + /// A parameter was incorrect. + #[stable(feature = "rust1", since = "1.0.0")] + InvalidInput, + /// Data not valid for the operation were encountered. + /// + /// Unlike [`InvalidInput`], this typically means that the operation + /// parameters were valid, however the error was caused by malformed + /// input data. + /// + /// For example, a function that reads a file into a string will error with + /// `InvalidData` if the file's contents are not valid UTF-8. + /// + /// [`InvalidInput`]: ErrorKind::InvalidInput + #[stable(feature = "io_invalid_data", since = "1.2.0")] + InvalidData, + /// The I/O operation's timeout expired, causing it to be canceled. + #[stable(feature = "rust1", since = "1.0.0")] + TimedOut, + // FIXME: restore links to `write` when trait is moved to `alloc` + /// An error returned when an operation could not be completed because a + /// call to [`write`] returned [`Ok(0)`]. + /// + /// This typically means that an operation could only succeed if it wrote a + /// particular number of bytes but only a smaller number of bytes could be + /// written. + /// + /// [`write`]: crate::io::Write::write + /// [`Ok(0)`]: Ok + #[stable(feature = "rust1", since = "1.0.0")] + WriteZero, + /// The underlying storage (typically, a filesystem) is full. + /// + /// This does not include out of quota errors. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + StorageFull, + /// Seek on unseekable file. + /// + /// Seeking was attempted on an open file handle which is not suitable for seeking - for + /// example, on Unix, a named pipe opened with `File::open`. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + NotSeekable, + /// Filesystem quota or some other kind of quota was exceeded. + #[stable(feature = "io_error_quota_exceeded", since = "1.85.0")] + QuotaExceeded, + /// File larger than allowed or supported. + /// + /// This might arise from a hard limit of the underlying filesystem or file access API, or from + /// an administratively imposed resource limitation. Simple disk full, and out of quota, have + /// their own errors. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + FileTooLarge, + /// Resource is busy. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + ResourceBusy, + /// Executable file is busy. + /// + /// An attempt was made to write to a file which is also in use as a running program. (Not all + /// operating systems detect this situation.) + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + ExecutableFileBusy, + /// Deadlock (avoided). + /// + /// A file locking operation would result in deadlock. This situation is typically detected, if + /// at all, on a best-effort basis. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + Deadlock, + /// Cross-device or cross-filesystem (hard) link or rename. + #[stable(feature = "io_error_crosses_devices", since = "1.85.0")] + CrossesDevices, + /// Too many (hard) links to the same filesystem object. + /// + /// The filesystem does not support making so many hardlinks to the same file. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + TooManyLinks, + /// A filename was invalid. + /// + /// This error can also occur if a length limit for a name was exceeded. + #[stable(feature = "io_error_invalid_filename", since = "1.87.0")] + InvalidFilename, + /// Program argument list too long. + /// + /// When trying to run an external program, a system or process limit on the size of the + /// arguments would have been exceeded. + #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] + ArgumentListTooLong, + /// This operation was interrupted. + /// + /// Interrupted operations can typically be retried. + #[stable(feature = "rust1", since = "1.0.0")] + Interrupted, + + /// This operation is unsupported on this platform. + /// + /// This means that the operation can never succeed. + #[stable(feature = "unsupported_error", since = "1.53.0")] + Unsupported, + + // ErrorKinds which are primarily categorisations for OS error + // codes should be added above. + // + /// An error returned when an operation could not be completed because an + /// "end of file" was reached prematurely. + /// + /// This typically means that an operation could only succeed if it read a + /// particular number of bytes but only a smaller number of bytes could be + /// read. + #[stable(feature = "read_exact", since = "1.6.0")] + UnexpectedEof, + + /// An operation could not be completed, because it failed + /// to allocate enough memory. + #[stable(feature = "out_of_memory_error", since = "1.54.0")] + OutOfMemory, + + /// The operation was partially successful and needs to be checked + /// later on due to not blocking. + #[unstable(feature = "io_error_inprogress", issue = "130840")] + InProgress, + + // "Unusual" error kinds which do not correspond simply to (sets + // of) OS error codes, should be added just above this comment. + // `Other` and `Uncategorized` should remain at the end: + // + /// A custom error that does not fall under any other I/O error kind. + /// + /// This can be used to construct your own [`Error`]s that do not match any + /// [`ErrorKind`]. + /// + /// This [`ErrorKind`] is not used by the standard library. + /// + /// Errors from the standard library that do not fall under any of the I/O + /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern. + /// New [`ErrorKind`]s might be added in the future for some of those. + #[stable(feature = "rust1", since = "1.0.0")] + Other, + + /// Any I/O error from the standard library that's not part of this list. + /// + /// Errors that are `Uncategorized` now may move to a different or a new + /// [`ErrorKind`] variant in the future. It is not recommended to match + /// an error against `Uncategorized`; use a wildcard match (`_`) instead. + #[unstable(feature = "io_error_uncategorized", issue = "none")] + #[doc(hidden)] + Uncategorized, +} + +impl ErrorKind { + pub(crate) fn as_str(&self) -> &'static str { + use ErrorKind::*; + match *self { + // tidy-alphabetical-start + AddrInUse => "address in use", + AddrNotAvailable => "address not available", + AlreadyExists => "entity already exists", + ArgumentListTooLong => "argument list too long", + BrokenPipe => "broken pipe", + ConnectionAborted => "connection aborted", + ConnectionRefused => "connection refused", + ConnectionReset => "connection reset", + CrossesDevices => "cross-device link or rename", + Deadlock => "deadlock", + DirectoryNotEmpty => "directory not empty", + ExecutableFileBusy => "executable file busy", + FileTooLarge => "file too large", + FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", + HostUnreachable => "host unreachable", + InProgress => "in progress", + Interrupted => "operation interrupted", + InvalidData => "invalid data", + InvalidFilename => "invalid filename", + InvalidInput => "invalid input parameter", + IsADirectory => "is a directory", + NetworkDown => "network down", + NetworkUnreachable => "network unreachable", + NotADirectory => "not a directory", + NotConnected => "not connected", + NotFound => "entity not found", + NotSeekable => "seek on unseekable file", + Other => "other error", + OutOfMemory => "out of memory", + PermissionDenied => "permission denied", + QuotaExceeded => "quota exceeded", + ReadOnlyFilesystem => "read-only filesystem or storage medium", + ResourceBusy => "resource busy", + StaleNetworkFileHandle => "stale network file handle", + StorageFull => "no storage space", + TimedOut => "timed out", + TooManyLinks => "too many links", + Uncategorized => "uncategorized error", + UnexpectedEof => "unexpected end of file", + Unsupported => "unsupported", + WouldBlock => "operation would block", + WriteZero => "write zero", + // tidy-alphabetical-end + } + } +} + +#[stable(feature = "io_errorkind_display", since = "1.60.0")] +impl fmt::Display for ErrorKind { + /// Shows a human-readable description of the `ErrorKind`. + /// + /// This is similar to `impl Display for Error`, but doesn't require first converting to Error. + /// + /// # Examples + /// ``` + /// use std::io::ErrorKind; + /// assert_eq!("entity not found", ErrorKind::NotFound.to_string()); + /// ``` + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str(self.as_str()) + } +} + +/// Intended for use for errors not exposed to the user, where allocating onto +/// the heap (for normal construction via Error::new) is too costly. +#[stable(feature = "io_error_from_errorkind", since = "1.14.0")] +impl From for Error { + /// Converts an [`ErrorKind`] into an [`Error`]. + /// + /// This conversion creates a new error with a simple representation of error kind. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// let not_found = ErrorKind::NotFound; + /// let error = Error::from(not_found); + /// assert_eq!("entity not found", format!("{error}")); + /// ``` + #[inline] + fn from(kind: ErrorKind) -> Error { + Error { repr: Repr::new_simple(kind) } + } +} + +impl Error { + /// Creates a new I/O error from a known kind of error as well as an + /// arbitrary error payload. + /// + /// This function is used to generically create I/O errors which do not + /// originate from the OS itself. The `error` argument is an arbitrary + /// payload which will be contained in this [`Error`]. + /// + /// Note that this function allocates memory on the heap. + /// If no extra payload is required, use the `From` conversion from + /// `ErrorKind`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// // errors can be created from strings + /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); + /// + /// // errors can also be created from other errors + /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); + /// + /// // creating an error without payload (and without memory allocation) + /// let eof_error = Error::from(ErrorKind::UnexpectedEof); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")] + #[inline(never)] + pub fn new(kind: ErrorKind, error: E) -> Error + where + E: Into>, + { + Self::_new(kind, error.into()) + } + + /// Creates a new I/O error from an arbitrary error payload. + /// + /// This function is used to generically create I/O errors which do not + /// originate from the OS itself. It is a shortcut for [`Error::new`] + /// with [`ErrorKind::Other`]. + /// + /// # Examples + /// + /// ``` + /// use std::io::Error; + /// + /// // errors can be created from strings + /// let custom_error = Error::other("oh no!"); + /// + /// // errors can also be created from other errors + /// let custom_error2 = Error::other(custom_error); + /// ``` + #[stable(feature = "io_error_other", since = "1.74.0")] + pub fn other(error: E) -> Error + where + E: Into>, + { + Self::_new(ErrorKind::Other, error.into()) + } + + fn _new(kind: ErrorKind, error: Box) -> Error { + Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) } + } + + /// Creates a new I/O error from a known kind of error as well as a constant + /// message. + /// + /// This function does not allocate. + /// + /// You should not use this directly, and instead use the `const_error!` + /// macro: `io::const_error!(ErrorKind::Something, "some_message")`. + /// + /// This function should maybe change to `from_static_message(kind: ErrorKind)` in the future, when const generics allow that. + #[inline] + #[doc(hidden)] + #[unstable(feature = "io_const_error_internals", issue = "none")] + pub const fn from_static_message(msg: &'static SimpleMessage) -> Error { + Self { repr: Repr::new_simple_message(msg) } + } + + #[unstable(feature = "io_error_internals", issue = "none")] + #[inline] + #[must_use] + #[doc(hidden)] + #[cfg(target_has_atomic = "ptr")] + pub fn _from_raw_os_error(code: RawOsError, os: &'static os::OsFunctions) -> Error { + os::set_functions(os); + Error { repr: Repr::new_os(code) } + } + + #[unstable(feature = "io_error_internals", issue = "none")] + #[must_use] + #[inline] + #[doc(hidden)] + pub fn _raw_os_error(&self) -> Option { + match self.repr.data() { + ErrorData::Os(i) => Some(i), + ErrorData::Custom(..) => None, + ErrorData::Simple(..) => None, + ErrorData::SimpleMessage(..) => None, + } + } + + /// Returns a reference to the inner error wrapped by this error (if any). + /// + /// If this [`Error`] was constructed via [`new`] then this function will + /// return [`Some`], otherwise it will return [`None`]. + /// + /// [`new`]: Error::new + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: &Error) { + /// if let Some(inner_err) = err.get_ref() { + /// println!("Inner error: {inner_err:?}"); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(&Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(&Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` + #[stable(feature = "io_error_inner", since = "1.3.0")] + #[must_use] + #[inline] + pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> { + match self.repr.data() { + ErrorData::Os(..) => None, + ErrorData::Simple(..) => None, + ErrorData::SimpleMessage(..) => None, + ErrorData::Custom(c) => Some(&*c.error), + } + } + + /// Returns a mutable reference to the inner error wrapped by this error + /// (if any). + /// + /// If this [`Error`] was constructed via [`new`] then this function will + /// return [`Some`], otherwise it will return [`None`]. + /// + /// [`new`]: Error::new + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// use std::{error, fmt}; + /// use std::fmt::Display; + /// + /// #[derive(Debug)] + /// struct MyError { + /// v: String, + /// } + /// + /// impl MyError { + /// fn new() -> MyError { + /// MyError { + /// v: "oh no!".to_string() + /// } + /// } + /// + /// fn change_message(&mut self, new_message: &str) { + /// self.v = new_message.to_string(); + /// } + /// } + /// + /// impl error::Error for MyError {} + /// + /// impl Display for MyError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "MyError: {}", self.v) + /// } + /// } + /// + /// fn change_error(mut err: Error) -> Error { + /// if let Some(inner_err) = err.get_mut() { + /// inner_err.downcast_mut::().unwrap().change_message("I've been changed!"); + /// } + /// err + /// } + /// + /// fn print_error(err: &Error) { + /// if let Some(inner_err) = err.get_ref() { + /// println!("Inner error: {inner_err}"); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(&change_error(Error::last_os_error())); + /// // Will print "Inner error: ...". + /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new()))); + /// } + /// ``` + #[stable(feature = "io_error_inner", since = "1.3.0")] + #[must_use] + #[inline] + pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> { + match self.repr.data_mut() { + ErrorData::Os(..) => None, + ErrorData::Simple(..) => None, + ErrorData::SimpleMessage(..) => None, + ErrorData::Custom(c) => Some(&mut *c.error), + } + } + + /// Consumes the `Error`, returning its inner error (if any). + /// + /// If this [`Error`] was constructed via [`new`] or [`other`], + /// then this function will return [`Some`], + /// otherwise it will return [`None`]. + /// + /// [`new`]: Error::new + /// [`other`]: Error::other + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: Error) { + /// if let Some(inner_err) = err.into_inner() { + /// println!("Inner error: {inner_err}"); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` + #[stable(feature = "io_error_inner", since = "1.3.0")] + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub fn into_inner(self) -> Option> { + match self.repr.into_data() { + ErrorData::Os(..) => None, + ErrorData::Simple(..) => None, + ErrorData::SimpleMessage(..) => None, + ErrorData::Custom(c) => Some(c.error), + } + } + + /// Attempts to downcast the custom boxed error to `E`. + /// + /// If this [`Error`] contains a custom boxed error, + /// then it would attempt downcasting on the boxed error, + /// otherwise it will return [`Err`]. + /// + /// If the custom boxed error has the same type as `E`, it will return [`Ok`], + /// otherwise it will also return [`Err`]. + /// + /// This method is meant to be a convenience routine for calling + /// `Box::downcast` on the custom boxed error, returned by + /// [`Error::into_inner`]. + /// + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// use std::io; + /// use std::error::Error; + /// + /// #[derive(Debug)] + /// enum E { + /// Io(io::Error), + /// SomeOtherVariant, + /// } + /// + /// impl fmt::Display for E { + /// // ... + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # todo!() + /// # } + /// } + /// impl Error for E {} + /// + /// impl From for E { + /// fn from(err: io::Error) -> E { + /// err.downcast::() + /// .unwrap_or_else(E::Io) + /// } + /// } + /// + /// impl From for io::Error { + /// fn from(err: E) -> io::Error { + /// match err { + /// E::Io(io_error) => io_error, + /// e => io::Error::new(io::ErrorKind::Other, e), + /// } + /// } + /// } + /// + /// # fn main() { + /// let e = E::SomeOtherVariant; + /// // Convert it to an io::Error + /// let io_error = io::Error::from(e); + /// // Cast it back to the original variant + /// let e = E::from(io_error); + /// assert!(matches!(e, E::SomeOtherVariant)); + /// + /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists); + /// // Convert it to E + /// let e = E::from(io_error); + /// // Cast it back to the original variant + /// let io_error = io::Error::from(e); + /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists); + /// assert!(io_error.get_ref().is_none()); + /// assert!(io_error.raw_os_error().is_none()); + /// # } + /// ``` + #[stable(feature = "io_error_downcast", since = "1.79.0")] + pub fn downcast(self) -> result::Result + where + E: error::Error + Send + Sync + 'static, + { + if let ErrorData::Custom(c) = self.repr.data() + && c.error.is::() + { + if let ErrorData::Custom(b) = self.repr.into_data() + && let Ok(err) = b.error.downcast::() + { + Ok(*err) + } else { + // Safety: We have just checked that the condition is true + unsafe { core::hint::unreachable_unchecked() } + } + } else { + Err(self) + } + } + + /// Returns the corresponding [`ErrorKind`] for this error. + /// + /// This may be a value set by Rust code constructing custom `io::Error`s, + /// or if this `io::Error` was sourced from the operating system, + /// it will be a value inferred from the system's error encoding. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: Error) { + /// println!("{:?}", err.kind()); + /// } + /// + /// fn main() { + /// // As no error has (visibly) occurred, this may print anything! + /// // It likely prints a placeholder for unidentified (non-)errors. + /// print_error(Error::last_os_error()); + /// // Will print "AddrInUse". + /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[inline] + pub fn kind(&self) -> ErrorKind { + match self.repr.data() { + ErrorData::Os(code) => os::decode_error_kind(code), + ErrorData::Custom(c) => c.kind, + ErrorData::Simple(kind) => kind, + ErrorData::SimpleMessage(m) => m.kind, + } + } + + #[unstable(feature = "io_error_internals", issue = "none")] + #[doc(hidden)] + #[inline] + pub fn is_interrupted(&self) -> bool { + match self.repr.data() { + ErrorData::Os(code) => os::is_interrupted(code), + ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted, + ErrorData::Simple(kind) => kind == ErrorKind::Interrupted, + ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted, + } + } +} + +impl fmt::Debug for Repr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.data() { + ErrorData::Os(code) => fmt + .debug_struct("Os") + .field("code", &code) + .field("kind", &os::decode_error_kind(code)) + .field("message", &os::error_string(code)) + .finish(), + ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt), + ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), + ErrorData::SimpleMessage(msg) => fmt + .debug_struct("Error") + .field("kind", &msg.kind) + .field("message", &msg.message) + .finish(), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.repr.data() { + ErrorData::Os(code) => { + let detail = os::error_string(code); + write!(fmt, "{detail} (os error {code})") + } + ErrorData::Custom(ref c) => c.error.fmt(fmt), + ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()), + ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl error::Error for Error { + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn error::Error> { + match self.repr.data() { + ErrorData::Os(..) => None, + ErrorData::Simple(..) => None, + ErrorData::SimpleMessage(..) => None, + ErrorData::Custom(c) => c.error.cause(), + } + } + + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self.repr.data() { + ErrorData::Os(..) => None, + ErrorData::Simple(..) => None, + ErrorData::SimpleMessage(..) => None, + ErrorData::Custom(c) => c.error.source(), + } + } +} + +fn _assert_error_is_sync_send() { + fn _is_sync_send() {} + _is_sync_send::(); +} diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/alloc/src/io/error/repr_bitpacked.rs similarity index 99% rename from library/std/src/io/error/repr_bitpacked.rs rename to library/alloc/src/io/error/repr_bitpacked.rs index 7353816a8171b..9759bd33e654e 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/alloc/src/io/error/repr_bitpacked.rs @@ -107,6 +107,7 @@ use core::num::NonZeroUsize; use core::ptr::NonNull; use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage}; +use crate::boxed::Box; // The 2 least-significant bits are used as tag. const TAG_MASK: usize = 0b11; diff --git a/library/std/src/io/error/repr_unpacked.rs b/library/alloc/src/io/error/repr_unpacked.rs similarity index 97% rename from library/std/src/io/error/repr_unpacked.rs rename to library/alloc/src/io/error/repr_unpacked.rs index b3e7b5f024ea0..59e51e97951cc 100644 --- a/library/std/src/io/error/repr_unpacked.rs +++ b/library/alloc/src/io/error/repr_unpacked.rs @@ -3,6 +3,7 @@ //! would have no benefit. use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage}; +use crate::boxed::Box; type Inner = ErrorData>; @@ -13,6 +14,7 @@ impl Repr { pub(super) fn new_custom(b: Box) -> Self { Self(Inner::Custom(b)) } + #[allow(dead_code)] #[inline] pub(super) fn new_os(code: RawOsError) -> Self { Self(Inner::Os(code)) diff --git a/library/std/src/io/impls.rs b/library/alloc/src/io/impls.rs similarity index 90% rename from library/std/src/io/impls.rs rename to library/alloc/src/io/impls.rs index d0245f3d4984c..5c35008ebf6c6 100644 --- a/library/std/src/io/impls.rs +++ b/library/alloc/src/io/impls.rs @@ -1,10 +1,15 @@ #[cfg(test)] mod tests; +use core::{cmp, fmt, mem, str}; + use crate::alloc::Allocator; +use crate::boxed::Box; use crate::collections::VecDeque; use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; -use crate::{cmp, fmt, mem, str}; +use crate::string::String; +use crate::sync::Arc; +use crate::vec::Vec; // ============================================================================= // Forwarding implementations @@ -286,6 +291,72 @@ impl BufRead for Box { (**self).read_line(buf) } } +#[stable(feature = "arc_io_traits", since = "CURRENT_RUSTC_VERSION")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] +impl Read for Arc +where + R: Read, + for<'a> &'a R: Read, +{ + fn read(&mut self, buf: &mut [u8]) -> io::Result { + (&**self).read(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + (&**self).read_vectored(bufs) + } + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + (&**self).read_buf(cursor) + } + #[inline] + fn is_read_vectored(&self) -> bool { + (&**self).is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + (&**self).read_to_end(buf) + } + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + (&**self).read_to_string(buf) + } +} +#[stable(feature = "arc_io_traits", since = "CURRENT_RUSTC_VERSION")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] +impl Write for Arc +where + W: Write, + for<'a> &'a W: Write, +{ + fn write(&mut self, buf: &[u8]) -> io::Result { + (&**self).write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&**self).write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + (&**self).is_write_vectored() + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + (&**self).flush() + } +} +#[stable(feature = "arc_io_traits", since = "CURRENT_RUSTC_VERSION")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] +impl Seek for Arc +where + S: Seek, + for<'a> &'a S: Seek, +{ + fn seek(&mut self, pos: SeekFrom) -> io::Result { + (&**self).seek(pos) + } + fn stream_len(&mut self) -> io::Result { + (&**self).stream_len() + } + fn stream_position(&mut self) -> io::Result { + (&**self).stream_position() + } +} // ============================================================================= // In-memory buffer implementations diff --git a/library/std/src/sys/io/io_slice/iovec.rs b/library/alloc/src/io/io_slice/iovec.rs similarity index 86% rename from library/std/src/sys/io/io_slice/iovec.rs rename to library/alloc/src/io/io_slice/iovec.rs index d549aca250d5f..13fedb050fe01 100644 --- a/library/std/src/sys/io/io_slice/iovec.rs +++ b/library/alloc/src/io/io_slice/iovec.rs @@ -1,13 +1,13 @@ -#[cfg(target_os = "hermit")] -use hermit_abi::iovec; -#[cfg(any(target_family = "unix", target_os = "trusty", target_os = "wasi"))] -use libc::iovec; +use core::ffi::c_void; +use core::marker::PhantomData; +use core::slice; -use crate::ffi::c_void; -use crate::marker::PhantomData; -use crate::slice; -#[cfg(target_os = "solid_asp3")] -use crate::sys::pal::abi::sockets::iovec; +#[derive(Copy, Clone)] +#[repr(C)] +struct iovec { + iov_base: *mut c_void, + iov_len: usize, +} #[derive(Copy, Clone)] #[repr(transparent)] diff --git a/library/alloc/src/io/io_slice/mod.rs b/library/alloc/src/io/io_slice/mod.rs new file mode 100644 index 0000000000000..05ac400c9dd97 --- /dev/null +++ b/library/alloc/src/io/io_slice/mod.rs @@ -0,0 +1,28 @@ +//! Target-dependant definition of `IoSlice` and `IoSliceMut` +//! +//! This is necessary to do it in `alloc` because other parts of the crate need +//! them even though they must have different layouts depending on the platform. +//! +//! However, we take great care to not leak platform-specific details and to not +//! link to any library here. + +#![allow(unreachable_pub)] + +cfg_select! { + any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => { + mod iovec; + pub use iovec::*; + } + target_os = "windows" => { + mod windows; + pub use windows::*; + } + target_os = "uefi" => { + mod uefi; + pub use uefi::*; + } + _ => { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/io/io_slice/uefi.rs b/library/alloc/src/io/io_slice/uefi.rs similarity index 97% rename from library/std/src/sys/io/io_slice/uefi.rs rename to library/alloc/src/io/io_slice/uefi.rs index 909cfbea0b7ba..739a98a4cea31 100644 --- a/library/std/src/sys/io/io_slice/uefi.rs +++ b/library/alloc/src/io/io_slice/uefi.rs @@ -1,8 +1,8 @@ //! A buffer type used with `Write::write_vectored` for UEFI Networking APIs. Vectored writing to //! File is not supported as of UEFI Spec 2.11. -use crate::marker::PhantomData; -use crate::slice; +use core::marker::PhantomData; +use core::slice; #[derive(Copy, Clone)] #[repr(C)] diff --git a/library/std/src/sys/io/io_slice/unsupported.rs b/library/alloc/src/io/io_slice/unsupported.rs similarity index 93% rename from library/std/src/sys/io/io_slice/unsupported.rs rename to library/alloc/src/io/io_slice/unsupported.rs index 1572cac6cd771..dd429a89d9a40 100644 --- a/library/std/src/sys/io/io_slice/unsupported.rs +++ b/library/alloc/src/io/io_slice/unsupported.rs @@ -1,5 +1,3 @@ -use crate::mem; - #[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); @@ -30,7 +28,7 @@ impl<'a> IoSliceMut<'a> { #[inline] pub fn advance(&mut self, n: usize) { - let slice = mem::take(&mut self.0); + let slice = core::mem::take(&mut self.0); let (_, remaining) = slice.split_at_mut(n); self.0 = remaining; } diff --git a/library/std/src/sys/io/io_slice/windows.rs b/library/alloc/src/io/io_slice/windows.rs similarity index 82% rename from library/std/src/sys/io/io_slice/windows.rs rename to library/alloc/src/io/io_slice/windows.rs index c3d8ec87c19e3..69cf68aabe23b 100644 --- a/library/std/src/sys/io/io_slice/windows.rs +++ b/library/alloc/src/io/io_slice/windows.rs @@ -1,11 +1,17 @@ -use crate::marker::PhantomData; -use crate::slice; -use crate::sys::c; +use core::marker::PhantomData; +use core::slice; + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct WSABUF { + pub len: u32, + pub buf: *mut u8, +} #[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { - vec: c::WSABUF, + vec: WSABUF, _p: PhantomData<&'a [u8]>, } @@ -14,7 +20,7 @@ impl<'a> IoSlice<'a> { pub fn new(buf: &'a [u8]) -> IoSlice<'a> { assert!(buf.len() <= u32::MAX as usize); IoSlice { - vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 }, + vec: WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 }, _p: PhantomData, } } @@ -39,7 +45,7 @@ impl<'a> IoSlice<'a> { #[repr(transparent)] pub struct IoSliceMut<'a> { - vec: c::WSABUF, + vec: WSABUF, _p: PhantomData<&'a mut [u8]>, } @@ -47,10 +53,7 @@ impl<'a> IoSliceMut<'a> { #[inline] pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { assert!(buf.len() <= u32::MAX as usize); - IoSliceMut { - vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() }, - _p: PhantomData, - } + IoSliceMut { vec: WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() }, _p: PhantomData } } #[inline] diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs new file mode 100644 index 0000000000000..42347d2a974d0 --- /dev/null +++ b/library/alloc/src/io/mod.rs @@ -0,0 +1,3122 @@ +//! Traits, helpers, and type definitions for core I/O functionality. + +use core::cmp; +#[unstable(feature = "read_buf", issue = "78485")] +pub use core::io::{BorrowedBuf, BorrowedCursor}; +use core::mem::{MaybeUninit, take}; +use core::ops::{Deref, DerefMut}; +use core::slice::memchr; + +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] +pub use self::buffered::WriterPanicked; +pub use self::buffered::{BufReader, BufWriter, IntoInnerError, LineWriter}; +pub use self::copy::copy; +pub use self::cursor::Cursor; +#[doc(hidden)] +#[unstable(feature = "io_const_error_internals", issue = "none")] +pub use self::error::SimpleMessage; +#[unstable(feature = "io_const_error", issue = "133448")] +pub use self::error::const_error; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::error::{Error, ErrorKind, Result}; +#[unstable(feature = "io_error_internals", issue = "none")] +#[doc(hidden)] +#[cfg(target_has_atomic = "ptr")] +pub use self::error::{RawOsError, os::OsFunctions}; +pub use self::util::{Empty, Repeat, Sink, empty, repeat, sink}; +use crate::boxed::Box; +use crate::fmt; +use crate::string::String; +use crate::vec::Vec; + +mod buffered; +mod copy; +mod cursor; +mod error; +mod impls; +mod io_slice; +pub mod prelude; +mod util; + +// Bare metal platforms usually have very small amounts of RAM +// (in the order of hundreds of KB) +#[unstable(feature = "io_internals", issue = "none")] +#[doc(hidden)] +pub const DEFAULT_BUF_SIZE: usize = cfg_select! { + target_os = "espidf" => 512, + _ => 8 * 1024, +}; + +struct Guard<'a> { + buf: &'a mut Vec, + len: usize, +} + +impl Drop for Guard<'_> { + fn drop(&mut self) { + unsafe { + self.buf.set_len(self.len); + } + } +} + +// Several `read_to_string` and `read_line` methods in the standard library will +// append data into a `String` buffer, but we need to be pretty careful when +// doing this. The implementation will just call `.as_mut_vec()` and then +// delegate to a byte-oriented reading method, but we must ensure that when +// returning we never leave `buf` in a state such that it contains invalid UTF-8 +// in its bounds. +// +// To this end, we use an RAII guard (to protect against panics) which updates +// the length of the string when it is dropped. This guard initially truncates +// the string to the prior length and only after we've validated that the +// new contents are valid UTF-8 do we allow it to set a longer length. +// +// The unsafety in this function is twofold: +// +// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8 +// checks. +// 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. +pub(crate) unsafe fn append_to_string(buf: &mut String, f: F) -> Result +where + F: FnOnce(&mut Vec) -> Result, +{ + let mut g = Guard { len: buf.len(), buf: unsafe { buf.as_mut_vec() } }; + let ret = f(g.buf); + + // SAFETY: the caller promises to only append data to `buf` + let appended = unsafe { g.buf.get_unchecked(g.len..) }; + if str::from_utf8(appended).is_err() { + ret.and_then(|_| Err(Error::INVALID_UTF8)) + } else { + g.len = g.buf.len(); + ret + } +} + +// Here we must serve many masters with conflicting goals: +// +// - avoid allocating unless necessary +// - avoid overallocating if we know the exact size (#89165) +// - avoid passing large buffers to readers that always initialize the free capacity if they perform short reads (#23815, #23820) +// - pass large buffers to readers that do not initialize the spare capacity. this can amortize per-call overheads +// - and finally pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems +// at the same time, i.e. small reads suffer from syscall overhead, all reads incur costs proportional to buffer size (#110650) +// +#[unstable(feature = "io_internals", issue = "none")] +#[doc(hidden)] +pub fn default_read_to_end( + r: &mut R, + buf: &mut Vec, + size_hint: Option, +) -> Result { + let start_len = buf.len(); + let start_cap = buf.capacity(); + // Optionally limit the maximum bytes read on each iteration. + // This adds an arbitrary fiddle factor to allow for more data than we expect. + let mut max_read_size = size_hint + .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE)) + .unwrap_or(DEFAULT_BUF_SIZE); + + let mut initialized = 0; // Extra initialized bytes from previous loop iteration + + const PROBE_SIZE: usize = 32; + + fn small_probe_read(r: &mut R, buf: &mut Vec) -> Result { + let mut probe = [0u8; PROBE_SIZE]; + + loop { + match r.read(&mut probe) { + Ok(n) => { + // there is no way to recover from allocation failure here + // because the data has already been read. + buf.extend_from_slice(&probe[..n]); + return Ok(n); + } + Err(ref e) if e.is_interrupted() => continue, + Err(e) => return Err(e), + } + } + } + + // avoid inflating empty/small vecs before we have determined that there's anything to read + if (size_hint.is_none() || size_hint == Some(0)) && buf.capacity() - buf.len() < PROBE_SIZE { + let read = small_probe_read(r, buf)?; + + if read == 0 { + return Ok(0); + } + } + + let mut consecutive_short_reads = 0; + + loop { + if buf.len() == buf.capacity() && buf.capacity() == start_cap { + // The buffer might be an exact fit. Let's read into a probe buffer + // and see if it returns `Ok(0)`. If so, we've avoided an + // unnecessary doubling of the capacity. But if not, append the + // probe buffer to the primary buffer and let its capacity grow. + let read = small_probe_read(r, buf)?; + + if read == 0 { + return Ok(buf.len() - start_len); + } + } + + if buf.len() == buf.capacity() { + // buf is full, need more space + buf.try_reserve(PROBE_SIZE)?; + } + + let mut spare = buf.spare_capacity_mut(); + let buf_len = cmp::min(spare.len(), max_read_size); + spare = &mut spare[..buf_len]; + let mut read_buf: BorrowedBuf<'_> = spare.into(); + + // SAFETY: These bytes were initialized but not filled in the previous loop + unsafe { + read_buf.set_init(initialized); + } + + let mut cursor = read_buf.unfilled(); + let result = loop { + match r.read_buf(cursor.reborrow()) { + Err(e) if e.is_interrupted() => continue, + // Do not stop now in case of error: we might have received both data + // and an error + res => break res, + } + }; + + let unfilled_but_initialized = cursor.init_mut().len(); + let bytes_read = cursor.written(); + let was_fully_initialized = read_buf.init_len() == buf_len; + + // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. + unsafe { + let new_len = bytes_read + buf.len(); + buf.set_len(new_len); + } + + // Now that all data is pushed to the vector, we can fail without data loss + result?; + + if bytes_read == 0 { + return Ok(buf.len() - start_len); + } + + if bytes_read < buf_len { + consecutive_short_reads += 1; + } else { + consecutive_short_reads = 0; + } + + // store how much was initialized but not filled + initialized = unfilled_but_initialized; + + // Use heuristics to determine the max read size if no initial size hint was provided + if size_hint.is_none() { + // The reader is returning short reads but it doesn't call ensure_init(). + // In that case we no longer need to restrict read sizes to avoid + // initialization costs. + // When reading from disk we usually don't get any short reads except at EOF. + // So we wait for at least 2 short reads before uncapping the read buffer; + // this helps with the Windows issue. + if !was_fully_initialized && consecutive_short_reads > 1 { + max_read_size = usize::MAX; + } + + // we have passed a larger buffer than previously and the + // reader still hasn't returned a short read + if buf_len >= max_read_size && bytes_read == buf_len { + max_read_size = max_read_size.saturating_mul(2); + } + } + } +} + +#[unstable(feature = "io_internals", issue = "none")] +#[doc(hidden)] +pub fn default_read_to_string( + r: &mut R, + buf: &mut String, + size_hint: Option, +) -> Result { + // Note that we do *not* call `r.read_to_end()` here. We are passing + // `&mut Vec` (the raw contents of `buf`) into the `read_to_end` + // method to fill it up. An arbitrary implementation could overwrite the + // entire contents of the vector, not just append to it (which is what + // we are expecting). + // + // To prevent extraneously checking the UTF-8-ness of the entire buffer + // we pass it to our hardcoded `default_read_to_end` implementation which + // we know is guaranteed to only read data into the end of the buffer. + unsafe { append_to_string(buf, |b| default_read_to_end(r, b, size_hint)) } +} + +#[unstable(feature = "io_internals", issue = "none")] +#[doc(hidden)] +pub fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result +where + F: FnOnce(&mut [u8]) -> Result, +{ + let buf = bufs.iter_mut().find(|b| !b.is_empty()).map_or(&mut [][..], |b| &mut **b); + read(buf) +} + +#[unstable(feature = "io_internals", issue = "none")] +#[doc(hidden)] +pub fn default_write_vectored(write: F, bufs: &[IoSlice<'_>]) -> Result +where + F: FnOnce(&[u8]) -> Result, +{ + let buf = bufs.iter().find(|b| !b.is_empty()).map_or(&[][..], |b| &**b); + write(buf) +} + +pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [u8]) -> Result<()> { + while !buf.is_empty() { + match this.read(buf) { + Ok(0) => break, + Ok(n) => { + buf = &mut buf[n..]; + } + Err(ref e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { Err(Error::READ_EXACT_EOF) } else { Ok(()) } +} + +#[unstable(feature = "io_internals", issue = "none")] +#[doc(hidden)] +pub fn default_read_buf(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()> +where + F: FnOnce(&mut [u8]) -> Result, +{ + let n = read(cursor.ensure_init().init_mut())?; + cursor.advance(n); + Ok(()) +} + +pub(crate) fn default_read_buf_exact( + this: &mut R, + mut cursor: BorrowedCursor<'_>, +) -> Result<()> { + while cursor.capacity() > 0 { + let prev_written = cursor.written(); + match this.read_buf(cursor.reborrow()) { + Ok(()) => {} + Err(e) if e.is_interrupted() => continue, + Err(e) => return Err(e), + } + + if cursor.written() == prev_written { + return Err(Error::READ_EXACT_EOF); + } + } + + Ok(()) +} + +pub(crate) fn default_write_fmt( + this: &mut W, + args: fmt::Arguments<'_>, +) -> Result<()> { + // Create a shim which translates a `Write` to a `fmt::Write` and saves off + // I/O errors, instead of discarding them. + struct Adapter<'a, T: ?Sized + 'a> { + inner: &'a mut T, + error: Result<()>, + } + + impl fmt::Write for Adapter<'_, T> { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write_all(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } + } + + let mut output = Adapter { inner: this, error: Ok(()) }; + match fmt::write(&mut output, args) { + Ok(()) => Ok(()), + Err(..) => { + // Check whether the error came from the underlying `Write`. + if output.error.is_err() { + output.error + } else { + // This shouldn't happen: the underlying stream did not error, + // but somehow the formatter still errored? + panic!( + "a formatting trait implementation returned an error when the underlying stream did not" + ); + } + } + } +} + +/// The `Read` trait allows for reading bytes from a source. +/// +/// Implementors of the `Read` trait are called 'readers'. +/// +/// Readers are defined by one required method, [`read()`]. Each call to [`read()`] +/// will attempt to pull bytes from this source into a provided buffer. A +/// number of other methods are implemented in terms of [`read()`], giving +/// implementors a number of ways to read bytes while only needing to implement +/// a single method. +/// +/// Readers are intended to be composable with one another. Many implementors +/// throughout [`std::io`] take and provide types which implement the `Read` +/// trait. +/// +/// Please note that each call to [`read()`] may involve a system call, and +/// therefore, using something that implements [`BufRead`], such as +/// [`BufReader`], will be more efficient. +/// +/// Repeated calls to the reader use the same cursor, so for example +/// calling `read_to_end` twice on a [`File`] will only return the file's +/// contents once. It's recommended to first call `rewind()` in that case. +/// +/// # Examples +/// +/// [`File`]s implement `Read`: +/// +/// ```no_run +/// use std::io; +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// fn main() -> io::Result<()> { +/// let mut f = File::open("foo.txt")?; +/// let mut buffer = [0; 10]; +/// +/// // read up to 10 bytes +/// f.read(&mut buffer)?; +/// +/// let mut buffer = Vec::new(); +/// // read the whole file +/// f.read_to_end(&mut buffer)?; +/// +/// // read into a String, so that you don't need to do the conversion. +/// let mut buffer = String::new(); +/// f.read_to_string(&mut buffer)?; +/// +/// // and more! See the other methods for more details. +/// Ok(()) +/// } +/// ``` +/// +/// Read from [`&str`] because [`&[u8]`][prim@slice] implements `Read`: +/// +/// ```no_run +/// # use std::io; +/// use std::io::prelude::*; +/// +/// fn main() -> io::Result<()> { +/// let mut b = "This string will be read".as_bytes(); +/// let mut buffer = [0; 10]; +/// +/// // read up to 10 bytes +/// b.read(&mut buffer)?; +/// +/// // etc... it works exactly as a File does! +/// Ok(()) +/// } +/// ``` +/// +/// [`read()`]: Read::read +/// [`&str`]: prim@str +/// [`std::io`]: self +/// [`File`]: crate::fs::File +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoRead")] +pub trait Read { + /// Pull some bytes from this source into the specified buffer, returning + /// how many bytes were read. + /// + /// This function does not provide any guarantees about whether it blocks + /// waiting for data, but if an object needs to block for a read and cannot, + /// it will typically signal this via an [`Err`] return value. + /// + /// If the return value of this method is [`Ok(n)`], then implementations must + /// guarantee that `0 <= n <= buf.len()`. A nonzero `n` value indicates + /// that the buffer `buf` has been filled in with `n` bytes of data from this + /// source. If `n` is `0`, then it can indicate one of two scenarios: + /// + /// 1. This reader has reached its "end of file" and will likely no longer + /// be able to produce bytes. Note that this does not mean that the + /// reader will *always* no longer be able to produce bytes. As an example, + /// on Linux, this method will call the `recv` syscall for a [`TcpStream`], + /// where returning zero indicates the connection was shut down correctly. While + /// for [`File`], it is possible to reach the end of file and get zero as result, + /// but if more data is appended to the file, future calls to `read` will return + /// more data. + /// 2. The buffer specified was 0 bytes in length. + /// + /// It is not an error if the returned value `n` is smaller than the buffer size, + /// even when the reader is not at the end of the stream yet. + /// This may happen for example because fewer bytes are actually available right now + /// (e. g. being close to end-of-file) or because read() was interrupted by a signal. + /// + /// As this trait is safe to implement, callers in unsafe code cannot rely on + /// `n <= buf.len()` for safety. + /// Extra care needs to be taken when `unsafe` functions are used to access the read bytes. + /// Callers have to ensure that no unchecked out-of-bounds accesses are possible even if + /// `n > buf.len()`. + /// + /// *Implementations* of this method can make no assumptions about the contents of `buf` when + /// this function is called. It is recommended that implementations only write data to `buf` + /// instead of reading its contents. + /// + /// Correspondingly, however, *callers* of this method in unsafe code must not assume + /// any guarantees about how the implementation uses `buf`. The trait is safe to implement, + /// so it is possible that the code that's supposed to write to the buffer might also read + /// from it. It is your responsibility to make sure that `buf` is initialized + /// before calling `read`. Calling `read` with an uninitialized `buf` (of the kind one + /// obtains via [`MaybeUninit`]) is not safe, and can lead to undefined behavior. + /// + /// [`MaybeUninit`]: crate::mem::MaybeUninit + /// + /// # Errors + /// + /// If this function encounters any form of I/O or other error, an error + /// variant will be returned. If an error is returned then it must be + /// guaranteed that no bytes were read. + /// + /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read + /// operation should be retried if there is nothing else to do. + /// + /// # Examples + /// + /// [`File`]s implement `Read`: + /// + /// [`Ok(n)`]: Ok + /// [`File`]: crate::fs::File + /// [`TcpStream`]: crate::net::TcpStream + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; + /// + /// // read up to 10 bytes + /// let n = f.read(&mut buffer[..])?; + /// + /// println!("The bytes: {:?}", &buffer[..n]); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn read(&mut self, buf: &mut [u8]) -> Result; + + /// Like `read`, except that it reads into a slice of buffers. + /// + /// Data is copied to fill each buffer in order, with the final buffer + /// written to possibly being only partially filled. This method must + /// behave equivalently to a single call to `read` with concatenated + /// buffers. + /// + /// The default implementation calls `read` with either the first nonempty + /// buffer provided, or an empty one if none exists. + #[stable(feature = "iovec", since = "1.36.0")] + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + default_read_vectored(|b| self.read(b), bufs) + } + + /// Determines if this `Read`er has an efficient `read_vectored` + /// implementation. + /// + /// If a `Read`er does not override the default `read_vectored` + /// implementation, code using it may want to avoid the method all together + /// and coalesce writes into a single buffer for higher performance. + /// + /// The default implementation returns `false`. + #[unstable(feature = "can_vector", issue = "69941")] + fn is_read_vectored(&self) -> bool { + false + } + + /// Reads all bytes until EOF in this source, placing them into `buf`. + /// + /// All bytes read from this source will be appended to the specified buffer + /// `buf`. This function will continuously call [`read()`] to append more data to + /// `buf` until [`read()`] returns either [`Ok(0)`] or an error of + /// non-[`ErrorKind::Interrupted`] kind. + /// + /// If successful, this function will return the total number of bytes read. + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`ErrorKind::Interrupted`] then the error is ignored and the operation + /// will continue. + /// + /// If any other read error is encountered then this function immediately + /// returns. Any bytes which have already been read will be appended to + /// `buf`. + /// + /// # Examples + /// + /// [`File`]s implement `Read`: + /// + /// [`read()`]: Read::read + /// [`Ok(0)`]: Ok + /// [`File`]: crate::fs::File + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = Vec::new(); + /// + /// // read the whole file + /// f.read_to_end(&mut buffer)?; + /// Ok(()) + /// } + /// ``` + /// + /// (See also the [`std::fs::read`] convenience function for reading from a + /// file.) + /// + /// [`std::fs::read`]: crate::fs::read + /// + /// ## Implementing `read_to_end` + /// + /// When implementing the `io::Read` trait, it is recommended to allocate + /// memory using [`Vec::try_reserve`]. However, this behavior is not guaranteed + /// by all implementations, and `read_to_end` may not handle out-of-memory + /// situations gracefully. + /// + /// ```no_run + /// # use std::io::{self, BufRead}; + /// # struct Example { example_datasource: io::Empty } impl Example { + /// # fn get_some_data_for_the_example(&self) -> &'static [u8] { &[] } + /// fn read_to_end(&mut self, dest_vec: &mut Vec) -> io::Result { + /// let initial_vec_len = dest_vec.len(); + /// loop { + /// let src_buf = self.example_datasource.fill_buf()?; + /// if src_buf.is_empty() { + /// break; + /// } + /// dest_vec.try_reserve(src_buf.len())?; + /// dest_vec.extend_from_slice(src_buf); + /// + /// // Any irreversible side effects should happen after `try_reserve` succeeds, + /// // to avoid losing data on allocation error. + /// let read = src_buf.len(); + /// self.example_datasource.consume(read); + /// } + /// Ok(dest_vec.len() - initial_vec_len) + /// } + /// # } + /// ``` + /// + /// # Usage Notes + /// + /// `read_to_end` attempts to read a source until EOF, but many sources are continuous streams + /// that do not send EOF. In these cases, `read_to_end` will block indefinitely. Standard input + /// is one such stream which may be finite if piped, but is typically continuous. For example, + /// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. + /// Reading user input or running programs that remain open indefinitely will never terminate + /// the stream with `EOF` (e.g. `yes | my-rust-program`). + /// + /// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution + /// + ///[`read`]: Read::read + /// + /// [`Vec::try_reserve`]: crate::vec::Vec::try_reserve + #[stable(feature = "rust1", since = "1.0.0")] + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + default_read_to_end(self, buf, None) + } + + /// Reads all bytes until EOF in this source, appending them to `buf`. + /// + /// If successful, this function returns the number of bytes which were read + /// and appended to `buf`. + /// + /// # Errors + /// + /// If the data in this stream is *not* valid UTF-8 then an error is + /// returned and `buf` is unchanged. + /// + /// See [`read_to_end`] for other error semantics. + /// + /// [`read_to_end`]: Read::read_to_end + /// + /// # Examples + /// + /// [`File`]s implement `Read`: + /// + /// [`File`]: crate::fs::File + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = String::new(); + /// + /// f.read_to_string(&mut buffer)?; + /// Ok(()) + /// } + /// ``` + /// + /// (See also the [`std::fs::read_to_string`] convenience function for + /// reading from a file.) + /// + /// # Usage Notes + /// + /// `read_to_string` attempts to read a source until EOF, but many sources are continuous streams + /// that do not send EOF. In these cases, `read_to_string` will block indefinitely. Standard input + /// is one such stream which may be finite if piped, but is typically continuous. For example, + /// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. + /// Reading user input or running programs that remain open indefinitely will never terminate + /// the stream with `EOF` (e.g. `yes | my-rust-program`). + /// + /// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution + /// + ///[`read`]: Read::read + /// + /// [`std::fs::read_to_string`]: crate::fs::read_to_string + #[stable(feature = "rust1", since = "1.0.0")] + fn read_to_string(&mut self, buf: &mut String) -> Result { + default_read_to_string(self, buf, None) + } + + /// Reads the exact number of bytes required to fill `buf`. + /// + /// This function reads as many bytes as necessary to completely fill the + /// specified buffer `buf`. + /// + /// *Implementations* of this method can make no assumptions about the contents of `buf` when + /// this function is called. It is recommended that implementations only write data to `buf` + /// instead of reading its contents. The documentation on [`read`] has a more detailed + /// explanation of this subject. + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`ErrorKind::Interrupted`] then the error is ignored and the operation + /// will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// The contents of `buf` are unspecified in this case. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + /// + /// # Examples + /// + /// [`File`]s implement `Read`: + /// + /// [`read`]: Read::read + /// [`File`]: crate::fs::File + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; + /// + /// // read exactly 10 bytes + /// f.read_exact(&mut buffer)?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "read_exact", since = "1.6.0")] + fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { + default_read_exact(self, buf) + } + + /// Pull some bytes from this source into the specified buffer. + /// + /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use + /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`. + /// + /// The default implementation delegates to `read`. + /// + /// This method makes it possible to return both data and an error but it is advised against. + #[unstable(feature = "read_buf", issue = "78485")] + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { + default_read_buf(|b| self.read(b), buf) + } + + /// Reads the exact number of bytes required to fill `cursor`. + /// + /// This is similar to the [`read_exact`](Read::read_exact) method, except + /// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use + /// with uninitialized buffers. + /// + /// # Errors + /// + /// If this function encounters an error of the kind [`ErrorKind::Interrupted`] + /// then the error is ignored and the operation will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// + /// If any other read error is encountered then this function immediately + /// returns. + /// + /// If this function returns an error, all bytes read will be appended to `cursor`. + #[unstable(feature = "read_buf", issue = "78485")] + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> { + default_read_buf_exact(self, cursor) + } + + /// Creates a "by reference" adapter for this instance of `Read`. + /// + /// The returned adapter also implements `Read` and will simply borrow this + /// current reader. + /// + /// # Examples + /// + /// [`File`]s implement `Read`: + /// + /// [`File`]: crate::fs::File + /// + /// ```no_run + /// use std::io; + /// use std::io::Read; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = Vec::new(); + /// let mut other_buffer = Vec::new(); + /// + /// { + /// let reference = f.by_ref(); + /// + /// // read at most 5 bytes + /// reference.take(5).read_to_end(&mut buffer)?; + /// + /// } // drop our &mut reference so we can use f again + /// + /// // original file still usable, read the rest + /// f.read_to_end(&mut other_buffer)?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn by_ref(&mut self) -> &mut Self + where + Self: Sized, + { + self + } + + /// Transforms this `Read` instance to an [`Iterator`] over its bytes. + /// + /// The returned type implements [`Iterator`] where the [`Item`] is + /// [Result]<[u8], [io::Error]>. + /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`] + /// otherwise. EOF is mapped to returning [`None`] from this iterator. + /// + /// The default implementation calls `read` for each byte, + /// which can be very inefficient for data that's not in memory, + /// such as [`File`]. Consider using a [`BufReader`] in such cases. + /// + /// # Examples + /// + /// [`File`]s implement `Read`: + /// + /// [`Item`]: Iterator::Item + /// [`File`]: crate::fs::File "fs::File" + /// [Result]: crate::result::Result "Result" + /// [io::Error]: self::Error "io::Error" + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let f = BufReader::new(File::open("foo.txt")?); + /// + /// for byte in f.bytes() { + /// println!("{}", byte?); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn bytes(self) -> Bytes + where + Self: Sized, + { + Bytes { inner: self } + } + + /// Creates an adapter which will chain this stream with another. + /// + /// The returned `Read` instance will first read all bytes from this object + /// until EOF is encountered. Afterwards the output is equivalent to the + /// output of `next`. + /// + /// # Examples + /// + /// [`File`]s implement `Read`: + /// + /// [`File`]: crate::fs::File + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let f1 = File::open("foo.txt")?; + /// let f2 = File::open("bar.txt")?; + /// + /// let mut handle = f1.chain(f2); + /// let mut buffer = String::new(); + /// + /// // read the value into a String. We could use any Read method here, + /// // this is just one example. + /// handle.read_to_string(&mut buffer)?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn chain(self, next: R) -> Chain + where + Self: Sized, + { + Chain { first: self, second: next, done_first: false } + } + + /// Creates an adapter which will read at most `limit` bytes from it. + /// + /// This function returns a new instance of `Read` which will read at most + /// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any + /// read errors will not count towards the number of bytes read and future + /// calls to [`read()`] may succeed. + /// + /// # Examples + /// + /// [`File`]s implement `Read`: + /// + /// [`File`]: crate::fs::File + /// [`Ok(0)`]: Ok + /// [`read()`]: Read::read + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let f = File::open("foo.txt")?; + /// let mut buffer = [0; 5]; + /// + /// // read at most five bytes + /// let mut handle = f.take(5); + /// + /// handle.read(&mut buffer)?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn take(self, limit: u64) -> Take + where + Self: Sized, + { + Take { inner: self, len: limit, limit } + } + + /// Read and return a fixed array of bytes from this source. + /// + /// This function uses an array sized based on a const generic size known at compile time. You + /// can specify the size with turbofish (`reader.read_array::<8>()`), or let type inference + /// determine the number of bytes needed based on how the return value gets used. For instance, + /// this function works well with functions like [`u64::from_le_bytes`] to turn an array of + /// bytes into an integer of the same size. + /// + /// Like `read_exact`, if this function encounters an "end of file" before reading the desired + /// number of bytes, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// + /// ``` + /// #![feature(read_array)] + /// use std::io::Cursor; + /// use std::io::prelude::*; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2]); + /// let x = u64::from_le_bytes(buf.read_array()?); + /// let y = u32::from_be_bytes(buf.read_array()?); + /// let z = u16::from_be_bytes(buf.read_array()?); + /// assert_eq!(x, 0x807060504030201); + /// assert_eq!(y, 0x9080706); + /// assert_eq!(z, 0x504); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "read_array", issue = "148848")] + fn read_array(&mut self) -> Result<[u8; N]> + where + Self: Sized, + { + let mut buf = [MaybeUninit::uninit(); N]; + let mut borrowed_buf = BorrowedBuf::from(buf.as_mut_slice()); + self.read_buf_exact(borrowed_buf.unfilled())?; + // Guard against incorrect `read_buf_exact` implementations. + assert_eq!(borrowed_buf.len(), N); + Ok(unsafe { MaybeUninit::array_assume_init(buf) }) + } +} + +/// Reads all bytes from a [reader][Read] into a new [`String`]. +/// +/// This is a convenience function for [`Read::read_to_string`]. Using this +/// function avoids having to create a variable first and provides more type +/// safety since you can only get the buffer out if there were no errors. (If you +/// use [`Read::read_to_string`] you have to remember to check whether the read +/// succeeded because otherwise your buffer will be empty or only partially full.) +/// +/// # Performance +/// +/// The downside of this function's increased ease of use and type safety is +/// that it gives you less control over performance. For example, you can't +/// pre-allocate memory like you can using [`String::with_capacity`] and +/// [`Read::read_to_string`]. Also, you can't re-use the buffer if an error +/// occurs while reading. +/// +/// In many cases, this function's performance will be adequate and the ease of use +/// and type safety tradeoffs will be worth it. However, there are cases where you +/// need more control over performance, and in those cases you should definitely use +/// [`Read::read_to_string`] directly. +/// +/// Note that in some special cases, such as when reading files, this function will +/// pre-allocate memory based on the size of the input it is reading. In those +/// cases, the performance should be as good as if you had used +/// [`Read::read_to_string`] with a manually pre-allocated buffer. +/// +/// # Errors +/// +/// This function forces you to handle errors because the output (the `String`) +/// is wrapped in a [`Result`]. See [`Read::read_to_string`] for the errors +/// that can occur. If any error occurs, you will get an [`Err`], so you +/// don't have to worry about your buffer being empty or partially full. +/// +/// # Examples +/// +/// ```no_run +/// # use std::io; +/// fn main() -> io::Result<()> { +/// let stdin = io::read_to_string(io::stdin())?; +/// println!("Stdin was:"); +/// println!("{stdin}"); +/// Ok(()) +/// } +/// ``` +/// +/// # Usage Notes +/// +/// `read_to_string` attempts to read a source until EOF, but many sources are continuous streams +/// that do not send EOF. In these cases, `read_to_string` will block indefinitely. Standard input +/// is one such stream which may be finite if piped, but is typically continuous. For example, +/// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. +/// Reading user input or running programs that remain open indefinitely will never terminate +/// the stream with `EOF` (e.g. `yes | my-rust-program`). +/// +/// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution +/// +///[`read`]: Read::read +/// +#[stable(feature = "io_read_to_string", since = "1.65.0")] +pub fn read_to_string(mut reader: R) -> Result { + let mut buf = String::new(); + reader.read_to_string(&mut buf)?; + Ok(buf) +} + +/// A buffer type used with `Read::read_vectored`. +/// It is semantically a wrapper around a `&mut [u8]`, but is guaranteed to be +/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on +/// Windows. +#[stable(feature = "iovec", since = "1.36.0")] +#[repr(transparent)] +pub struct IoSliceMut<'a>(io_slice::IoSliceMut<'a>); + +#[stable(feature = "iovec_send_sync", since = "1.44.0")] +unsafe impl<'a> Send for IoSliceMut<'a> {} + +#[stable(feature = "iovec_send_sync", since = "1.44.0")] +unsafe impl<'a> Sync for IoSliceMut<'a> {} + +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> fmt::Debug for IoSliceMut<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.0.as_slice(), fmt) + } +} + +impl<'a> IoSliceMut<'a> { + /// Creates a new `IoSliceMut` wrapping a byte slice. + /// + /// # Panics + /// + /// Panics on Windows if the slice is larger than 4GB. + #[stable(feature = "iovec", since = "1.36.0")] + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut(io_slice::IoSliceMut::new(buf)) + } + + /// Advance the internal cursor of the slice. + /// + /// Also see [`IoSliceMut::advance_slices`] to advance the cursors of + /// multiple buffers. + /// + /// # Panics + /// + /// Panics when trying to advance beyond the end of the slice. + /// + /// # Examples + /// + /// ``` + /// use std::io::IoSliceMut; + /// use std::ops::Deref; + /// + /// let mut data = [1; 8]; + /// let mut buf = IoSliceMut::new(&mut data); + /// + /// // Mark 3 bytes as read. + /// buf.advance(3); + /// assert_eq!(buf.deref(), [1; 5].as_ref()); + /// ``` + #[stable(feature = "io_slice_advance", since = "1.81.0")] + #[inline] + pub fn advance(&mut self, n: usize) { + self.0.advance(n) + } + + /// Advance a slice of slices. + /// + /// Shrinks the slice to remove any `IoSliceMut`s that are fully advanced over. + /// If the cursor ends up in the middle of an `IoSliceMut`, it is modified + /// to start at that cursor. + /// + /// For example, if we have a slice of two 8-byte `IoSliceMut`s, and we advance by 10 bytes, + /// the result will only include the second `IoSliceMut`, advanced by 2 bytes. + /// + /// # Panics + /// + /// Panics when trying to advance beyond the end of the slices. + /// + /// # Examples + /// + /// ``` + /// use std::io::IoSliceMut; + /// use std::ops::Deref; + /// + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// + /// // Mark 10 bytes as read. + /// IoSliceMut::advance_slices(&mut bufs, 10); + /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); + /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); + /// ``` + #[stable(feature = "io_slice_advance", since = "1.81.0")] + #[inline] + pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) { + // Number of buffers to remove. + let mut remove = 0; + // Remaining length before reaching n. + let mut left = n; + for buf in bufs.iter() { + if let Some(remainder) = left.checked_sub(buf.len()) { + left = remainder; + remove += 1; + } else { + break; + } + } + + *bufs = &mut take(bufs)[remove..]; + if bufs.is_empty() { + assert!(left == 0, "advancing io slices beyond their length"); + } else { + bufs[0].advance(left); + } + } + + /// Get the underlying bytes as a mutable slice with the original lifetime. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_slice_as_bytes)] + /// use std::io::IoSliceMut; + /// + /// let mut data = *b"abcdef"; + /// let io_slice = IoSliceMut::new(&mut data); + /// io_slice.into_slice()[0] = b'A'; + /// + /// assert_eq!(&data, b"Abcdef"); + /// ``` + #[unstable(feature = "io_slice_as_bytes", issue = "132818")] + pub const fn into_slice(self) -> &'a mut [u8] { + self.0.into_slice() + } +} + +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> Deref for IoSliceMut<'a> { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.0.as_slice() + } +} + +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> DerefMut for IoSliceMut<'a> { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + self.0.as_mut_slice() + } +} + +/// A buffer type used with `Write::write_vectored`. +/// +/// It is semantically a wrapper around a `&[u8]`, but is guaranteed to be +/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on +/// Windows. +#[stable(feature = "iovec", since = "1.36.0")] +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a>(io_slice::IoSlice<'a>); + +#[stable(feature = "iovec_send_sync", since = "1.44.0")] +unsafe impl<'a> Send for IoSlice<'a> {} + +#[stable(feature = "iovec_send_sync", since = "1.44.0")] +unsafe impl<'a> Sync for IoSlice<'a> {} + +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> fmt::Debug for IoSlice<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.0.as_slice(), fmt) + } +} + +impl<'a> IoSlice<'a> { + /// Creates a new `IoSlice` wrapping a byte slice. + /// + /// # Panics + /// + /// Panics on Windows if the slice is larger than 4GB. + #[stable(feature = "iovec", since = "1.36.0")] + #[must_use] + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice(io_slice::IoSlice::new(buf)) + } + + /// Advance the internal cursor of the slice. + /// + /// Also see [`IoSlice::advance_slices`] to advance the cursors of multiple + /// buffers. + /// + /// # Panics + /// + /// Panics when trying to advance beyond the end of the slice. + /// + /// # Examples + /// + /// ``` + /// use std::io::IoSlice; + /// use std::ops::Deref; + /// + /// let data = [1; 8]; + /// let mut buf = IoSlice::new(&data); + /// + /// // Mark 3 bytes as read. + /// buf.advance(3); + /// assert_eq!(buf.deref(), [1; 5].as_ref()); + /// ``` + #[stable(feature = "io_slice_advance", since = "1.81.0")] + #[inline] + pub fn advance(&mut self, n: usize) { + self.0.advance(n) + } + + /// Advance a slice of slices. + /// + /// Shrinks the slice to remove any `IoSlice`s that are fully advanced over. + /// If the cursor ends up in the middle of an `IoSlice`, it is modified + /// to start at that cursor. + /// + /// For example, if we have a slice of two 8-byte `IoSlice`s, and we advance by 10 bytes, + /// the result will only include the second `IoSlice`, advanced by 2 bytes. + /// + /// # Panics + /// + /// Panics when trying to advance beyond the end of the slices. + /// + /// # Examples + /// + /// ``` + /// use std::io::IoSlice; + /// use std::ops::Deref; + /// + /// let buf1 = [1; 8]; + /// let buf2 = [2; 16]; + /// let buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSlice::new(&buf1), + /// IoSlice::new(&buf2), + /// IoSlice::new(&buf3), + /// ][..]; + /// + /// // Mark 10 bytes as written. + /// IoSlice::advance_slices(&mut bufs, 10); + /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); + /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); + #[stable(feature = "io_slice_advance", since = "1.81.0")] + #[inline] + pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) { + // Number of buffers to remove. + let mut remove = 0; + // Remaining length before reaching n. This prevents overflow + // that could happen if the length of slices in `bufs` were instead + // accumulated. Those slice may be aliased and, if they are large + // enough, their added length may overflow a `usize`. + let mut left = n; + for buf in bufs.iter() { + if let Some(remainder) = left.checked_sub(buf.len()) { + left = remainder; + remove += 1; + } else { + break; + } + } + + *bufs = &mut take(bufs)[remove..]; + if bufs.is_empty() { + assert!(left == 0, "advancing io slices beyond their length"); + } else { + bufs[0].advance(left); + } + } + + /// Get the underlying bytes as a slice with the original lifetime. + /// + /// This doesn't borrow from `self`, so is less restrictive than calling + /// `.deref()`, which does. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_slice_as_bytes)] + /// use std::io::IoSlice; + /// + /// let data = b"abcdef"; + /// + /// let mut io_slice = IoSlice::new(data); + /// let tail = &io_slice.as_slice()[3..]; + /// + /// // This works because `tail` doesn't borrow `io_slice` + /// io_slice = IoSlice::new(tail); + /// + /// assert_eq!(io_slice.as_slice(), b"def"); + /// ``` + #[unstable(feature = "io_slice_as_bytes", issue = "132818")] + pub const fn as_slice(self) -> &'a [u8] { + self.0.as_slice() + } +} + +#[stable(feature = "iovec", since = "1.36.0")] +impl<'a> Deref for IoSlice<'a> { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.0.as_slice() + } +} + +/// A trait for objects which are byte-oriented sinks. +/// +/// Implementors of the `Write` trait are sometimes called 'writers'. +/// +/// Writers are defined by two required methods, [`write`] and [`flush`]: +/// +/// * The [`write`] method will attempt to write some data into the object, +/// returning how many bytes were successfully written. +/// +/// * The [`flush`] method is useful for adapters and explicit buffers +/// themselves for ensuring that all buffered data has been pushed out to the +/// 'true sink'. +/// +/// Writers are intended to be composable with one another. Many implementors +/// throughout [`std::io`] take and provide types which implement the `Write` +/// trait. +/// +/// [`write`]: Write::write +/// [`flush`]: Write::flush +/// [`std::io`]: self +/// +/// # Examples +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// fn main() -> std::io::Result<()> { +/// let data = b"some bytes"; +/// +/// let mut pos = 0; +/// let mut buffer = File::create("foo.txt")?; +/// +/// while pos < data.len() { +/// let bytes_written = buffer.write(&data[pos..])?; +/// pos += bytes_written; +/// } +/// Ok(()) +/// } +/// ``` +/// +/// The trait also provides convenience methods like [`write_all`], which calls +/// `write` in a loop until its entire input has been written. +/// +/// [`write_all`]: Write::write_all +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")] +pub trait Write { + /// Writes a buffer into this writer, returning how many bytes were written. + /// + /// This function will attempt to write the entire contents of `buf`, but + /// the entire write might not succeed, or the write may also generate an + /// error. Typically, a call to `write` represents one attempt to write to + /// any wrapped object. + /// + /// Calls to `write` are not guaranteed to block waiting for data to be + /// written, and a write which would otherwise block can be indicated through + /// an [`Err`] variant. + /// + /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. + /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`. + /// A return value of `Ok(0)` typically means that the underlying object is + /// no longer able to accept bytes and will likely not be able to in the + /// future as well, or that the buffer provided is empty. + /// + /// # Errors + /// + /// Each call to `write` may generate an I/O error indicating that the + /// operation could not be completed. If an error is returned then no bytes + /// in the buffer were written to this writer. + /// + /// It is **not** considered an error if the entire buffer could not be + /// written to this writer. + /// + /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the + /// write operation should be retried if there is nothing else to do. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// // Writes some prefix of the byte string, not necessarily all of it. + /// buffer.write(b"some bytes")?; + /// Ok(()) + /// } + /// ``` + /// + /// [`Ok(n)`]: Ok + #[stable(feature = "rust1", since = "1.0.0")] + fn write(&mut self, buf: &[u8]) -> Result; + + /// Like [`write`], except that it writes from a slice of buffers. + /// + /// Data is copied from each buffer in order, with the final buffer + /// read from possibly being only partially consumed. This method must + /// behave as a call to [`write`] with the buffers concatenated would. + /// + /// The default implementation calls [`write`] with either the first nonempty + /// buffer provided, or an empty one if none exists. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::IoSlice; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let data1 = [1; 8]; + /// let data2 = [15; 8]; + /// let io_slice1 = IoSlice::new(&data1); + /// let io_slice2 = IoSlice::new(&data2); + /// + /// let mut buffer = File::create("foo.txt")?; + /// + /// // Writes some prefix of the byte string, not necessarily all of it. + /// buffer.write_vectored(&[io_slice1, io_slice2])?; + /// Ok(()) + /// } + /// ``` + /// + /// [`write`]: Write::write + #[stable(feature = "iovec", since = "1.36.0")] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + default_write_vectored(|b| self.write(b), bufs) + } + + /// Determines if this `Write`r has an efficient [`write_vectored`] + /// implementation. + /// + /// If a `Write`r does not override the default [`write_vectored`] + /// implementation, code using it may want to avoid the method all together + /// and coalesce writes into a single buffer for higher performance. + /// + /// The default implementation returns `false`. + /// + /// [`write_vectored`]: Write::write_vectored + #[unstable(feature = "can_vector", issue = "69941")] + fn is_write_vectored(&self) -> bool { + false + } + + /// Flushes this output stream, ensuring that all intermediately buffered + /// contents reach their destination. + /// + /// # Errors + /// + /// It is considered an error if not all bytes could be written due to + /// I/O errors or EOF being reached. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::prelude::*; + /// use std::io::BufWriter; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = BufWriter::new(File::create("foo.txt")?); + /// + /// buffer.write_all(b"some bytes")?; + /// buffer.flush()?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn flush(&mut self) -> Result<()>; + + /// Attempts to write an entire buffer into this writer. + /// + /// This method will continuously call [`write`] until there is no more data + /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of [`ErrorKind::Interrupted`] kind generated from this method will be + /// returned. + /// + /// If the buffer contains no data, this will never call [`write`]. + /// + /// # Errors + /// + /// This function will return the first error of + /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns. + /// + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// buffer.write_all(b"some bytes")?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { + while !buf.is_empty() { + match self.write(buf) { + Ok(0) => { + return Err(Error::WRITE_ALL_EOF); + } + Ok(n) => buf = &buf[n..], + Err(ref e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Attempts to write multiple buffers into this writer. + /// + /// This method will continuously call [`write_vectored`] until there is no + /// more data to be written or an error of non-[`ErrorKind::Interrupted`] + /// kind is returned. This method will not return until all buffers have + /// been successfully written or such an error occurs. The first error that + /// is not of [`ErrorKind::Interrupted`] kind generated from this method + /// will be returned. + /// + /// If the buffer contains no data, this will never call [`write_vectored`]. + /// + /// # Notes + /// + /// Unlike [`write_vectored`], this takes a *mutable* reference to + /// a slice of [`IoSlice`]s, not an immutable one. That's because we need to + /// modify the slice to keep track of the bytes already written. + /// + /// Once this function returns, the contents of `bufs` are unspecified, as + /// this depends on how many calls to [`write_vectored`] were necessary. It is + /// best to understand this function as taking ownership of `bufs` and to + /// not use `bufs` afterwards. The underlying buffers, to which the + /// [`IoSlice`]s point (but not the [`IoSlice`]s themselves), are unchanged and + /// can be reused. + /// + /// [`write_vectored`]: Write::write_vectored + /// + /// # Examples + /// + /// ``` + /// #![feature(write_all_vectored)] + /// # fn main() -> std::io::Result<()> { + /// + /// use std::io::{Write, IoSlice}; + /// + /// let mut writer = Vec::new(); + /// let bufs = &mut [ + /// IoSlice::new(&[1]), + /// IoSlice::new(&[2, 3]), + /// IoSlice::new(&[4, 5, 6]), + /// ]; + /// + /// writer.write_all_vectored(bufs)?; + /// // Note: the contents of `bufs` is now undefined, see the Notes section. + /// + /// assert_eq!(writer, &[1, 2, 3, 4, 5, 6]); + /// # Ok(()) } + /// ``` + #[unstable(feature = "write_all_vectored", issue = "70436")] + fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> { + // Guarantee that bufs is empty if it contains no data, + // to avoid calling write_vectored if there is no data to be written. + IoSlice::advance_slices(&mut bufs, 0); + while !bufs.is_empty() { + match self.write_vectored(bufs) { + Ok(0) => { + return Err(Error::WRITE_ALL_EOF); + } + Ok(n) => IoSlice::advance_slices(&mut bufs, n), + Err(ref e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Writes a formatted string into this writer, returning any error + /// encountered. + /// + /// This method is primarily used to interface with the + /// [`format_args!()`] macro, and it is rare that this should + /// explicitly be called. The [`write!()`] macro should be favored to + /// invoke this method instead. + /// + /// This function internally uses the [`write_all`] method on + /// this trait and hence will continuously write data so long as no errors + /// are received. This also means that partial writes are not indicated in + /// this signature. + /// + /// [`write_all`]: Write::write_all + /// + /// # Errors + /// + /// This function will return any I/O error reported while formatting. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// // this call + /// write!(buffer, "{:.*}", 2, 1.234567)?; + /// // turns into this: + /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> { + if let Some(s) = args.as_statically_known_str() { + self.write_all(s.as_bytes()) + } else { + default_write_fmt(self, args) + } + } + + /// Creates a "by reference" adapter for this instance of `Write`. + /// + /// The returned adapter also implements `Write` and will simply borrow this + /// current writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::Write; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// let reference = buffer.by_ref(); + /// + /// // we can use reference just like our original buffer + /// reference.write_all(b"some bytes")?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn by_ref(&mut self) -> &mut Self + where + Self: Sized, + { + self + } +} + +/// The `Seek` trait provides a cursor which can be moved within a stream of +/// bytes. +/// +/// The stream typically has a fixed size, allowing seeking relative to either +/// end or the current offset. +/// +/// # Examples +/// +/// [`File`]s implement `Seek`: +/// +/// [`File`]: crate::fs::File +/// +/// ```no_run +/// use std::io; +/// use std::io::prelude::*; +/// use std::fs::File; +/// use std::io::SeekFrom; +/// +/// fn main() -> io::Result<()> { +/// let mut f = File::open("foo.txt")?; +/// +/// // move the cursor 42 bytes from the start of the file +/// f.seek(SeekFrom::Start(42))?; +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoSeek")] +pub trait Seek { + /// Seek to an offset, in bytes, in a stream. + /// + /// A seek beyond the end of a stream is allowed, but behavior is defined + /// by the implementation. + /// + /// If the seek operation completed successfully, + /// this method returns the new position from the start of the stream. + /// That position can be used later with [`SeekFrom::Start`]. + /// + /// # Errors + /// + /// Seeking can fail, for example because it might involve flushing a buffer. + /// + /// Seeking to a negative offset is considered an error. + #[stable(feature = "rust1", since = "1.0.0")] + fn seek(&mut self, pos: SeekFrom) -> Result; + + /// Rewind to the beginning of a stream. + /// + /// This is a convenience method, equivalent to `seek(SeekFrom::Start(0))`. + /// + /// # Errors + /// + /// Rewinding can fail, for example because it might involve flushing a buffer. + /// + /// # Example + /// + /// ```no_run + /// use std::io::{Read, Seek, Write}; + /// use std::fs::OpenOptions; + /// + /// let mut f = OpenOptions::new() + /// .write(true) + /// .read(true) + /// .create(true) + /// .open("foo.txt")?; + /// + /// let hello = "Hello!\n"; + /// write!(f, "{hello}")?; + /// f.rewind()?; + /// + /// let mut buf = String::new(); + /// f.read_to_string(&mut buf)?; + /// assert_eq!(&buf, hello); + /// # std::io::Result::Ok(()) + /// ``` + #[stable(feature = "seek_rewind", since = "1.55.0")] + fn rewind(&mut self) -> Result<()> { + self.seek(SeekFrom::Start(0))?; + Ok(()) + } + + /// Returns the length of this stream (in bytes). + /// + /// The default implementation uses up to three seek operations. If this + /// method returns successfully, the seek position is unchanged (i.e. the + /// position before calling this method is the same as afterwards). + /// However, if this method returns an error, the seek position is + /// unspecified. + /// + /// If you need to obtain the length of *many* streams and you don't care + /// about the seek position afterwards, you can reduce the number of seek + /// operations by simply calling `seek(SeekFrom::End(0))` and using its + /// return value (it is also the stream length). + /// + /// Note that length of a stream can change over time (for example, when + /// data is appended to a file). So calling this method multiple times does + /// not necessarily return the same length each time. + /// + /// # Example + /// + /// ```no_run + /// #![feature(seek_stream_len)] + /// use std::{ + /// io::{self, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// + /// let len = f.stream_len()?; + /// println!("The file is currently {len} bytes long"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "seek_stream_len", issue = "59359")] + fn stream_len(&mut self) -> Result { + stream_len_default(self) + } + + /// Returns the current seek position from the start of the stream. + /// + /// This is equivalent to `self.seek(SeekFrom::Current(0))`. + /// + /// # Example + /// + /// ```no_run + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "seek_convenience", since = "1.51.0")] + fn stream_position(&mut self) -> Result { + self.seek(SeekFrom::Current(0)) + } + + /// Seeks relative to the current position. + /// + /// This is equivalent to `self.seek(SeekFrom::Current(offset))` but + /// doesn't return the new position which can allow some implementations + /// such as [`BufReader`] to perform more efficient seeks. + /// + /// # Example + /// + /// ```no_run + /// use std::{ + /// io::{self, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// f.seek_relative(10)?; + /// assert_eq!(f.stream_position()?, 10); + /// Ok(()) + /// } + /// ``` + /// + /// [`BufReader`]: crate::io::BufReader + #[stable(feature = "seek_seek_relative", since = "1.80.0")] + fn seek_relative(&mut self, offset: i64) -> Result<()> { + self.seek(SeekFrom::Current(offset))?; + Ok(()) + } +} + +#[unstable(feature = "io_internals", issue = "none")] +#[doc(hidden)] +pub fn stream_len_default(self_: &mut T) -> Result { + let old_pos = self_.stream_position()?; + let len = self_.seek(SeekFrom::End(0))?; + + // Avoid seeking a third time when we were already at the end of the + // stream. The branch is usually way cheaper than a seek operation. + if old_pos != len { + self_.seek(SeekFrom::Start(old_pos))?; + } + + Ok(len) +} + +/// Enumeration of possible methods to seek within an I/O object. +/// +/// It is used by the [`Seek`] trait. +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")] +pub enum SeekFrom { + /// Sets the offset to the provided number of bytes. + #[stable(feature = "rust1", since = "1.0.0")] + Start(#[stable(feature = "rust1", since = "1.0.0")] u64), + + /// Sets the offset to the size of this object plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but it's an error to + /// seek before byte 0. + #[stable(feature = "rust1", since = "1.0.0")] + End(#[stable(feature = "rust1", since = "1.0.0")] i64), + + /// Sets the offset to the current position plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but it's an error to + /// seek before byte 0. + #[stable(feature = "rust1", since = "1.0.0")] + Current(#[stable(feature = "rust1", since = "1.0.0")] i64), +} + +fn read_until(r: &mut R, delim: u8, buf: &mut Vec) -> Result { + let mut read = 0; + loop { + let (done, used) = { + let available = match r.fill_buf() { + Ok(n) => n, + Err(ref e) if e.is_interrupted() => continue, + Err(e) => return Err(e), + }; + match memchr::memchr(delim, available) { + Some(i) => { + buf.extend_from_slice(&available[..=i]); + (true, i + 1) + } + None => { + buf.extend_from_slice(available); + (false, available.len()) + } + } + }; + r.consume(used); + read += used; + if done || used == 0 { + return Ok(read); + } + } +} + +fn skip_until(r: &mut R, delim: u8) -> Result { + let mut read = 0; + loop { + let (done, used) = { + let available = match r.fill_buf() { + Ok(n) => n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + }; + match memchr::memchr(delim, available) { + Some(i) => (true, i + 1), + None => (false, available.len()), + } + }; + r.consume(used); + read += used; + if done || used == 0 { + return Ok(read); + } + } +} + +/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it +/// to perform extra ways of reading. +/// +/// For example, reading line-by-line is inefficient without using a buffer, so +/// if you want to read by line, you'll need `BufRead`, which includes a +/// [`read_line`] method as well as a [`lines`] iterator. +/// +/// # Examples +/// +/// A locked standard input implements `BufRead`: +/// +/// ```no_run +/// use std::io; +/// use std::io::prelude::*; +/// +/// let stdin = io::stdin(); +/// for line in stdin.lock().lines() { +/// println!("{}", line?); +/// } +/// # std::io::Result::Ok(()) +/// ``` +/// +/// If you have something that implements [`Read`], you can use the [`BufReader` +/// type][`BufReader`] to turn it into a `BufRead`. +/// +/// For example, [`File`] implements [`Read`], but not `BufRead`. +/// [`BufReader`] to the rescue! +/// +/// [`File`]: crate::fs::File +/// [`read_line`]: BufRead::read_line +/// [`lines`]: BufRead::lines +/// +/// ```no_run +/// use std::io::{self, BufReader}; +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// fn main() -> io::Result<()> { +/// let f = File::open("foo.txt")?; +/// let f = BufReader::new(f); +/// +/// for line in f.lines() { +/// let line = line?; +/// println!("{line}"); +/// } +/// +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoBufRead")] +pub trait BufRead: Read { + /// Returns the contents of the internal buffer, filling it with more data, via `Read` methods, if empty. + /// + /// This is a lower-level method and is meant to be used together with [`consume`], + /// which can be used to mark bytes that should not be returned by subsequent calls to `read`. + /// + /// [`consume`]: BufRead::consume + /// + /// Returns an empty buffer when the stream has reached EOF. + /// + /// # Errors + /// + /// This function will return an I/O error if a `Read` method was called, but returned an error. + /// + /// # Examples + /// + /// A locked standard input implements `BufRead`: + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// + /// let buffer = stdin.fill_buf()?; + /// + /// // work with buffer + /// println!("{buffer:?}"); + /// + /// // mark the bytes we worked with as read + /// let length = buffer.len(); + /// stdin.consume(length); + /// # std::io::Result::Ok(()) + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn fill_buf(&mut self) -> Result<&[u8]>; + + /// Marks the given `amount` of additional bytes from the internal buffer as having been read. + /// Subsequent calls to `read` only return bytes that have not been marked as read. + /// + /// This is a lower-level method and is meant to be used together with [`fill_buf`], + /// which can be used to fill the internal buffer via `Read` methods. + /// + /// It is a logic error if `amount` exceeds the number of unread bytes in the internal buffer, which is returned by [`fill_buf`]. + /// + /// # Examples + /// + /// Since `consume()` is meant to be used with [`fill_buf`], + /// that method's example includes an example of `consume()`. + /// + /// [`fill_buf`]: BufRead::fill_buf + #[stable(feature = "rust1", since = "1.0.0")] + fn consume(&mut self, amount: usize); + + /// Checks if there is any data left to be `read`. + /// + /// This function may fill the buffer to check for data, + /// so this function returns `Result`, not `bool`. + /// + /// The default implementation calls `fill_buf` and checks that the + /// returned slice is empty (which means that there is no data left, + /// since EOF is reached). + /// + /// # Errors + /// + /// This function will return an I/O error if a `Read` method was called, but returned an error. + /// + /// Examples + /// + /// ``` + /// #![feature(buf_read_has_data_left)] + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// + /// while stdin.has_data_left()? { + /// let mut line = String::new(); + /// stdin.read_line(&mut line)?; + /// // work with line + /// println!("{line:?}"); + /// } + /// # std::io::Result::Ok(()) + /// ``` + #[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")] + fn has_data_left(&mut self) -> Result { + self.fill_buf().map(|b| !b.is_empty()) + } + + /// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. + /// + /// This function will read bytes from the underlying stream until the + /// delimiter or EOF is found. Once found, all bytes up to, and including, + /// the delimiter (if found) will be appended to `buf`. + /// + /// If successful, this function will return the total number of bytes read. + /// + /// This function is blocking and should be used carefully: it is possible for + /// an attacker to continuously send bytes without ever sending the delimiter + /// or EOF. + /// + /// # Errors + /// + /// This function will ignore all instances of [`ErrorKind::Interrupted`] and + /// will otherwise return any errors returned by [`fill_buf`]. + /// + /// If an I/O error is encountered then all bytes read so far will be + /// present in `buf` and its length will have been adjusted appropriately. + /// + /// [`fill_buf`]: BufRead::fill_buf + /// + /// # Examples + /// + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read all the bytes in a byte slice + /// in hyphen delimited segments: + /// + /// ``` + /// use std::io::{self, BufRead}; + /// + /// let mut cursor = io::Cursor::new(b"lorem-ipsum"); + /// let mut buf = vec![]; + /// + /// // cursor is at 'l' + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 6); + /// assert_eq!(buf, b"lorem-"); + /// buf.clear(); + /// + /// // cursor is at 'i' + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 5); + /// assert_eq!(buf, b"ipsum"); + /// buf.clear(); + /// + /// // cursor is at EOF + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 0); + /// assert_eq!(buf, b""); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { + read_until(self, byte, buf) + } + + /// Skips all bytes until the delimiter `byte` or EOF is reached. + /// + /// This function will read (and discard) bytes from the underlying stream until the + /// delimiter or EOF is found. + /// + /// If successful, this function will return the total number of bytes read, + /// including the delimiter byte if found. + /// + /// This is useful for efficiently skipping data such as NUL-terminated strings + /// in binary file formats without buffering. + /// + /// This function is blocking and should be used carefully: it is possible for + /// an attacker to continuously send bytes without ever sending the delimiter + /// or EOF. + /// + /// # Errors + /// + /// This function will ignore all instances of [`ErrorKind::Interrupted`] and + /// will otherwise return any errors returned by [`fill_buf`]. + /// + /// If an I/O error is encountered then all bytes read so far will be + /// present in `buf` and its length will have been adjusted appropriately. + /// + /// [`fill_buf`]: BufRead::fill_buf + /// + /// # Examples + /// + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read some NUL-terminated information + /// about Ferris from a binary string, skipping the fun fact: + /// + /// ``` + /// use std::io::{self, BufRead}; + /// + /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0!"); + /// + /// // read name + /// let mut name = Vec::new(); + /// let num_bytes = cursor.read_until(b'\0', &mut name) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 7); + /// assert_eq!(name, b"Ferris\0"); + /// + /// // skip fun fact + /// let num_bytes = cursor.skip_until(b'\0') + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 30); + /// + /// // read animal type + /// let mut animal = Vec::new(); + /// let num_bytes = cursor.read_until(b'\0', &mut animal) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 11); + /// assert_eq!(animal, b"Crustacean\0"); + /// + /// // reach EOF + /// let num_bytes = cursor.skip_until(b'\0') + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 1); + /// ``` + #[stable(feature = "bufread_skip_until", since = "1.83.0")] + fn skip_until(&mut self, byte: u8) -> Result { + skip_until(self, byte) + } + + /// Reads all bytes until a newline (the `0xA` byte) is reached, and append + /// them to the provided `String` buffer. + /// + /// Previous content of the buffer will be preserved. To avoid appending to + /// the buffer, you need to [`clear`] it first. + /// + /// This function will read bytes from the underlying stream until the + /// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes + /// up to, and including, the delimiter (if found) will be appended to + /// `buf`. + /// + /// If successful, this function will return the total number of bytes read. + /// + /// If this function returns [`Ok(0)`], the stream has reached EOF. + /// + /// This function is blocking and should be used carefully: it is possible for + /// an attacker to continuously send bytes without ever sending a newline + /// or EOF. You can use [`take`] to limit the maximum number of bytes read. + /// + /// [`Ok(0)`]: Ok + /// [`clear`]: String::clear + /// [`take`]: crate::io::Read::take + /// + /// # Errors + /// + /// This function has the same error semantics as [`read_until`] and will + /// also return an error if the read bytes are not valid UTF-8. If an I/O + /// error is encountered then `buf` may contain some bytes already read in + /// the event that all data read so far was valid UTF-8. + /// + /// [`read_until`]: BufRead::read_until + /// + /// # Examples + /// + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read all the lines in a byte slice: + /// + /// ``` + /// use std::io::{self, BufRead}; + /// + /// let mut cursor = io::Cursor::new(b"foo\nbar"); + /// let mut buf = String::new(); + /// + /// // cursor is at 'f' + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 4); + /// assert_eq!(buf, "foo\n"); + /// buf.clear(); + /// + /// // cursor is at 'b' + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 3); + /// assert_eq!(buf, "bar"); + /// buf.clear(); + /// + /// // cursor is at EOF + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 0); + /// assert_eq!(buf, ""); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn read_line(&mut self, buf: &mut String) -> Result { + // Note that we are not calling the `.read_until` method here, but + // rather our hardcoded implementation. For more details as to why, see + // the comments in `default_read_to_string`. + unsafe { append_to_string(buf, |b| read_until(self, b'\n', b)) } + } + + /// Returns an iterator over the contents of this reader split on the byte + /// `byte`. + /// + /// The iterator returned from this function will return instances of + /// [io::Result]<[Vec]\>. Each vector returned will *not* have + /// the delimiter byte at the end. + /// + /// This function will yield errors whenever [`read_until`] would have + /// also yielded an error. + /// + /// [io::Result]: self::Result "io::Result" + /// [`read_until`]: BufRead::read_until + /// + /// # Examples + /// + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to iterate over all hyphen delimited + /// segments in a byte slice + /// + /// ``` + /// use std::io::{self, BufRead}; + /// + /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor"); + /// + /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap()); + /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec())); + /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec())); + /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec())); + /// assert_eq!(split_iter.next(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn split(self, byte: u8) -> Split + where + Self: Sized, + { + Split { buf: self, delim: byte } + } + + /// Returns an iterator over the lines of this reader. + /// + /// The iterator returned from this function will yield instances of + /// [io::Result]<[String]>. Each string returned will *not* have a newline + /// byte (the `0xA` byte) or `CRLF` (`0xD`, `0xA` bytes) at the end. + /// + /// [io::Result]: self::Result "io::Result" + /// + /// # Examples + /// + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to iterate over all the lines in a byte + /// slice. + /// + /// ``` + /// use std::io::{self, BufRead}; + /// + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); + /// + /// let mut lines_iter = cursor.lines().map(|l| l.unwrap()); + /// assert_eq!(lines_iter.next(), Some(String::from("lorem"))); + /// assert_eq!(lines_iter.next(), Some(String::from("ipsum"))); + /// assert_eq!(lines_iter.next(), Some(String::from("dolor"))); + /// assert_eq!(lines_iter.next(), None); + /// ``` + /// + /// # Errors + /// + /// Each line of the iterator has the same error semantics as [`BufRead::read_line`]. + #[stable(feature = "rust1", since = "1.0.0")] + fn lines(self) -> Lines + where + Self: Sized, + { + Lines { buf: self } + } +} + +/// Adapter to chain together two readers. +/// +/// This struct is generally created by calling [`chain`] on a reader. +/// Please see the documentation of [`chain`] for more details. +/// +/// [`chain`]: Read::chain +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] +pub struct Chain { + first: T, + second: U, + done_first: bool, +} + +impl Chain { + /// Consumes the `Chain`, returning the wrapped readers. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.into_inner(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "more_io_inner_methods", since = "1.20.0")] + pub fn into_inner(self) -> (T, U) { + (self.first, self.second) + } + + /// Gets references to the underlying readers in this `Chain`. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "more_io_inner_methods", since = "1.20.0")] + pub fn get_ref(&self) -> (&T, &U) { + (&self.first, &self.second) + } + + /// Gets mutable references to the underlying readers in this `Chain`. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let mut chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_mut(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "more_io_inner_methods", since = "1.20.0")] + pub fn get_mut(&mut self) -> (&mut T, &mut U) { + (&mut self.first, &mut self.second) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Chain { + fn read(&mut self, buf: &mut [u8]) -> Result { + if !self.done_first { + match self.first.read(buf)? { + 0 if !buf.is_empty() => self.done_first = true, + n => return Ok(n), + } + } + self.second.read(buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + if !self.done_first { + match self.first.read_vectored(bufs)? { + 0 if bufs.iter().any(|b| !b.is_empty()) => self.done_first = true, + n => return Ok(n), + } + } + self.second.read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + self.first.is_read_vectored() || self.second.is_read_vectored() + } + + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + let mut read = 0; + if !self.done_first { + read += self.first.read_to_end(buf)?; + self.done_first = true; + } + read += self.second.read_to_end(buf)?; + Ok(read) + } + + // We don't override `read_to_string` here because an UTF-8 sequence could + // be split between the two parts of the chain + + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { + if buf.capacity() == 0 { + return Ok(()); + } + + if !self.done_first { + let old_len = buf.written(); + self.first.read_buf(buf.reborrow())?; + + if buf.written() != old_len { + return Ok(()); + } else { + self.done_first = true; + } + } + self.second.read_buf(buf) + } +} + +#[stable(feature = "chain_bufread", since = "1.9.0")] +impl BufRead for Chain { + fn fill_buf(&mut self) -> Result<&[u8]> { + if !self.done_first { + match self.first.fill_buf()? { + buf if buf.is_empty() => self.done_first = true, + buf => return Ok(buf), + } + } + self.second.fill_buf() + } + + fn consume(&mut self, amt: usize) { + if !self.done_first { self.first.consume(amt) } else { self.second.consume(amt) } + } + + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { + let mut read = 0; + if !self.done_first { + let n = self.first.read_until(byte, buf)?; + read += n; + + match buf.last() { + Some(b) if *b == byte && n != 0 => return Ok(read), + _ => self.done_first = true, + } + } + read += self.second.read_until(byte, buf)?; + Ok(read) + } + + // We don't override `read_line` here because an UTF-8 sequence could be + // split between the two parts of the chain +} + +impl SizeHint for Chain { + #[inline] + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) + } + + #[inline] + fn upper_bound(&self) -> Option { + match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { + (Some(first), Some(second)) => first.checked_add(second), + _ => None, + } + } +} + +/// Reader adapter which limits the bytes read from an underlying reader. +/// +/// This struct is generally created by calling [`take`] on a reader. +/// Please see the documentation of [`take`] for more details. +/// +/// [`take`]: Read::take +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] +pub struct Take { + inner: T, + len: u64, + limit: u64, +} + +impl Take { + /// Returns the number of bytes that can be read before this instance will + /// return EOF. + /// + /// # Note + /// + /// This instance may reach `EOF` after reading fewer bytes than indicated by + /// this method if the underlying [`Read`] instance reaches EOF. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let f = File::open("foo.txt")?; + /// + /// // read at most five bytes + /// let handle = f.take(5); + /// + /// println!("limit: {}", handle.limit()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn limit(&self) -> u64 { + self.limit + } + + /// Returns the number of bytes read so far. + #[unstable(feature = "seek_io_take_position", issue = "97227")] + pub fn position(&self) -> u64 { + self.len - self.limit + } + + /// Sets the number of bytes that can be read before this instance will + /// return EOF. This is the same as constructing a new `Take` instance, so + /// the amount of bytes read and the previous limit value don't matter when + /// calling this method. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let f = File::open("foo.txt")?; + /// + /// // read at most five bytes + /// let mut handle = f.take(5); + /// handle.set_limit(10); + /// + /// assert_eq!(handle.limit(), 10); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "take_set_limit", since = "1.27.0")] + pub fn set_limit(&mut self, limit: u64) { + self.len = limit; + self.limit = limit; + } + + /// Consumes the `Take`, returning the wrapped reader. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.into_inner(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "io_take_into_inner", since = "1.15.0")] + pub fn into_inner(self) -> T { + self.inner + } + + /// Gets a reference to the underlying reader. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying reader as doing so may corrupt the internal limit of this + /// `Take`. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "more_io_inner_methods", since = "1.20.0")] + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying reader. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying reader as doing so may corrupt the internal limit of this + /// `Take`. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.get_mut(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "more_io_inner_methods", since = "1.20.0")] + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Take { + fn read(&mut self, buf: &mut [u8]) -> Result { + // Don't call into inner reader at all at EOF because it may still block + if self.limit == 0 { + return Ok(0); + } + + let max = cmp::min(buf.len() as u64, self.limit) as usize; + let n = self.inner.read(&mut buf[..max])?; + assert!(n as u64 <= self.limit, "number of read bytes exceeds limit"); + self.limit -= n as u64; + Ok(n) + } + + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { + // Don't call into inner reader at all at EOF because it may still block + if self.limit == 0 { + return Ok(()); + } + + if self.limit < buf.capacity() as u64 { + // The condition above guarantees that `self.limit` fits in `usize`. + let limit = self.limit as usize; + + let extra_init = cmp::min(limit, buf.init_mut().len()); + + // SAFETY: no uninit data is written to ibuf + let ibuf = unsafe { &mut buf.as_mut()[..limit] }; + + let mut sliced_buf: BorrowedBuf<'_> = ibuf.into(); + + // SAFETY: extra_init bytes of ibuf are known to be initialized + unsafe { + sliced_buf.set_init(extra_init); + } + + let mut cursor = sliced_buf.unfilled(); + let result = self.inner.read_buf(cursor.reborrow()); + + let new_init = cursor.init_mut().len(); + let filled = sliced_buf.len(); + + // cursor / sliced_buf / ibuf must drop here + + unsafe { + // SAFETY: filled bytes have been filled and therefore initialized + buf.advance_unchecked(filled); + // SAFETY: new_init bytes of buf's unfilled buffer have been initialized + buf.set_init(new_init); + } + + self.limit -= filled as u64; + + result + } else { + let written = buf.written(); + let result = self.inner.read_buf(buf.reborrow()); + self.limit -= (buf.written() - written) as u64; + result + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for Take { + fn fill_buf(&mut self) -> Result<&[u8]> { + // Don't call into inner reader at all at EOF because it may still block + if self.limit == 0 { + return Ok(&[]); + } + + let buf = self.inner.fill_buf()?; + let cap = cmp::min(buf.len() as u64, self.limit) as usize; + Ok(&buf[..cap]) + } + + fn consume(&mut self, amt: usize) { + // Don't let callers reset the limit by passing an overlarge value + let amt = cmp::min(amt as u64, self.limit) as usize; + self.limit -= amt as u64; + self.inner.consume(amt); + } +} + +impl SizeHint for Take { + #[inline] + fn lower_bound(&self) -> usize { + cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize + } + + #[inline] + fn upper_bound(&self) -> Option { + match SizeHint::upper_bound(&self.inner) { + Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize), + None => self.limit.try_into().ok(), + } + } +} + +#[stable(feature = "seek_io_take", since = "1.89.0")] +impl Seek for Take { + fn seek(&mut self, pos: SeekFrom) -> Result { + let new_position = match pos { + SeekFrom::Start(v) => Some(v), + SeekFrom::Current(v) => self.position().checked_add_signed(v), + SeekFrom::End(v) => self.len.checked_add_signed(v), + }; + let new_position = match new_position { + Some(v) if v <= self.len => v, + _ => return Err(ErrorKind::InvalidInput.into()), + }; + while new_position != self.position() { + if let Some(offset) = new_position.checked_signed_diff(self.position()) { + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + break; + } + let offset = if new_position > self.position() { i64::MAX } else { i64::MIN }; + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + } + Ok(new_position) + } + + fn stream_len(&mut self) -> Result { + Ok(self.len) + } + + fn stream_position(&mut self) -> Result { + Ok(self.position()) + } + + fn seek_relative(&mut self, offset: i64) -> Result<()> { + if !self.position().checked_add_signed(offset).is_some_and(|p| p <= self.len) { + return Err(ErrorKind::InvalidInput.into()); + } + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + Ok(()) + } +} + +/// An iterator over `u8` values of a reader. +/// +/// This struct is generally created by calling [`bytes`] on a reader. +/// Please see the documentation of [`bytes`] for more details. +/// +/// [`bytes`]: Read::bytes +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] +pub struct Bytes { + inner: R, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Bytes { + type Item = Result; + + // Not `#[inline]`. This function gets inlined even without it, but having + // the inline annotation can result in worse code generation. See #116785. + fn next(&mut self) -> Option> { + SpecReadByte::spec_read_byte(&mut self.inner) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + SizeHint::size_hint(&self.inner) + } +} + +/// For the specialization of `Bytes::next`. + +#[unstable(feature = "io_internals", issue = "none")] +#[doc(hidden)] +pub trait SpecReadByte { + fn spec_read_byte(&mut self) -> Option>; +} + +impl SpecReadByte for R +where + Self: Read, +{ + #[inline] + default fn spec_read_byte(&mut self) -> Option> { + inlined_slow_read_byte(self) + } +} + +/// Reads a single byte in a slow, generic way. This is used by the default +/// `spec_read_byte`. +#[inline] +fn inlined_slow_read_byte(reader: &mut R) -> Option> { + let mut byte = 0; + loop { + return match reader.read(core::slice::from_mut(&mut byte)) { + Ok(0) => None, + Ok(..) => Some(Ok(byte)), + Err(ref e) if e.is_interrupted() => continue, + Err(e) => Some(Err(e)), + }; + } +} + +// Used by `BufReader::spec_read_byte`, for which the `inline(never)` is +// important. +#[inline(never)] +fn uninlined_slow_read_byte(reader: &mut R) -> Option> { + inlined_slow_read_byte(reader) +} + +trait SizeHint { + fn lower_bound(&self) -> usize; + + fn upper_bound(&self) -> Option; + + fn size_hint(&self) -> (usize, Option) { + (self.lower_bound(), self.upper_bound()) + } +} + +impl SizeHint for T { + #[inline] + default fn lower_bound(&self) -> usize { + 0 + } + + #[inline] + default fn upper_bound(&self) -> Option { + None + } +} + +impl SizeHint for &mut T { + #[inline] + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(*self) + } + + #[inline] + fn upper_bound(&self) -> Option { + SizeHint::upper_bound(*self) + } +} + +impl SizeHint for Box { + #[inline] + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(&**self) + } + + #[inline] + fn upper_bound(&self) -> Option { + SizeHint::upper_bound(&**self) + } +} + +impl SizeHint for &[u8] { + #[inline] + fn lower_bound(&self) -> usize { + self.len() + } + + #[inline] + fn upper_bound(&self) -> Option { + Some(self.len()) + } +} + +/// An iterator over the contents of an instance of `BufRead` split on a +/// particular byte. +/// +/// This struct is generally created by calling [`split`] on a `BufRead`. +/// Please see the documentation of [`split`] for more details. +/// +/// [`split`]: BufRead::split +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoSplit")] +pub struct Split { + buf: B, + delim: u8, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Split { + type Item = Result>; + + fn next(&mut self) -> Option>> { + let mut buf = Vec::new(); + match self.buf.read_until(self.delim, &mut buf) { + Ok(0) => None, + Ok(_n) => { + if buf[buf.len() - 1] == self.delim { + buf.pop(); + } + Some(Ok(buf)) + } + Err(e) => Some(Err(e)), + } + } +} + +/// An iterator over the lines of an instance of `BufRead`. +/// +/// This struct is generally created by calling [`lines`] on a `BufRead`. +/// Please see the documentation of [`lines`] for more details. +/// +/// [`lines`]: BufRead::lines +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoLines")] +pub struct Lines { + buf: B, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Lines { + type Item = Result; + + fn next(&mut self) -> Option> { + let mut buf = String::new(); + match self.buf.read_line(&mut buf) { + Ok(0) => None, + Ok(_n) => { + if buf.ends_with('\n') { + buf.pop(); + if buf.ends_with('\r') { + buf.pop(); + } + } + Some(Ok(buf)) + } + Err(e) => Some(Err(e)), + } + } +} diff --git a/library/std/src/io/prelude.rs b/library/alloc/src/io/prelude.rs similarity index 100% rename from library/std/src/io/prelude.rs rename to library/alloc/src/io/prelude.rs diff --git a/library/std/src/io/util.rs b/library/alloc/src/io/util.rs similarity index 99% rename from library/std/src/io/util.rs rename to library/alloc/src/io/util.rs index 0410df3ef1a3e..f894f53549ac1 100644 --- a/library/std/src/io/util.rs +++ b/library/alloc/src/io/util.rs @@ -7,6 +7,8 @@ use crate::fmt; use crate::io::{ self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write, }; +use crate::string::String; +use crate::vec::Vec; /// `Empty` ignores any data written via [`Write`], and will always be empty /// (returning zero bytes) when read via [`Read`]. diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index aff10c4320fe1..9f867d7e28534 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -63,7 +63,7 @@ #![doc( html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", - test(no_crate_inject, attr(allow(unused_variables, duplicate_features), deny(warnings))) + test(no_crate_inject, attr(allow(unused_variables, duplicate_features, dead_code))) )] #![doc(auto_cfg(hide(no_global_oom_handling, no_rc, no_sync, target_has_atomic = "ptr")))] #![doc(rust_logo)] @@ -86,6 +86,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(not(no_global_oom_handling), feature(io_const_error))] #![feature(allocator_api)] #![feature(array_into_iter_constructors)] #![feature(ascii_char)] @@ -109,6 +110,7 @@ #![feature(const_try)] #![feature(copied_into_inner)] #![feature(core_intrinsics)] +#![feature(core_io_borrowed_buf)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] #![feature(diagnostic_on_move)] @@ -132,6 +134,8 @@ #![feature(legacy_receiver_trait)] #![feature(likely_unlikely)] #![feature(local_waker)] +#![feature(maybe_uninit_array_assume_init)] +#![feature(maybe_uninit_fill)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(panic_internals)] #![feature(pattern)] @@ -197,6 +201,7 @@ // // Rustdoc features: #![feature(doc_cfg)] +#![feature(doc_notable_trait)] // Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]` // blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad // that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs @@ -222,10 +227,13 @@ pub mod boxed; #[unstable(feature = "bstr", issue = "134915")] pub mod bstr; pub mod collections; -#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))] +#[cfg(not(no_global_oom_handling))] pub mod ffi; pub mod fmt; pub mod intrinsics; +#[unstable(feature = "alloc_io", issue = "154046")] +#[cfg(not(no_global_oom_handling))] +pub mod io; #[cfg(not(no_rc))] pub mod rc; pub mod slice; diff --git a/library/std/src/io/buffered/tests.rs b/library/alloctests/tests/io/buffered.rs similarity index 97% rename from library/std/src/io/buffered/tests.rs rename to library/alloctests/tests/io/buffered.rs index e335d8afdc483..2d909c7ae4b4e 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/alloctests/tests/io/buffered.rs @@ -1,10 +1,10 @@ -use crate::io::prelude::*; -use crate::io::{ +use alloc::io::prelude::*; +use alloc::io::{ self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom, }; -use crate::mem::MaybeUninit; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::{panic, thread}; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicUsize, Ordering}; +use std::{panic, thread}; /// A dummy reader intended at testing short-reads propagation. pub struct ShortReader { @@ -515,29 +515,6 @@ fn panic_in_write_doesnt_flush_in_drop() { assert_eq!(WRITES.load(Ordering::SeqCst), 1); } -#[bench] -fn bench_buffered_reader(b: &mut test::Bencher) { - b.iter(|| BufReader::new(io::empty())); -} - -#[bench] -fn bench_buffered_reader_small_reads(b: &mut test::Bencher) { - let data = (0..u8::MAX).cycle().take(1024 * 4).collect::>(); - b.iter(|| { - let mut reader = BufReader::new(&data[..]); - let mut buf = [0u8; 4]; - for _ in 0..1024 { - reader.read_exact(&mut buf).unwrap(); - core::hint::black_box(&buf); - } - }); -} - -#[bench] -fn bench_buffered_writer(b: &mut test::Bencher) { - b.iter(|| BufWriter::new(io::sink())); -} - /// A simple `Write` target, designed to be wrapped by `LineWriter` / /// `BufWriter` / etc, that can have its `write` & `flush` behavior /// configured @@ -681,7 +658,7 @@ fn line_vectored() { #[test] fn line_vectored_partial_and_errors() { - use crate::collections::VecDeque; + use alloc::collections::VecDeque; enum Call { Write { inputs: Vec<&'static [u8]>, output: io::Result }, @@ -1023,7 +1000,7 @@ struct WriteRecorder { impl Write for WriteRecorder { fn write(&mut self, buf: &[u8]) -> io::Result { - use crate::str::from_utf8; + use core::str::from_utf8; self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string())); Ok(buf.len()) @@ -1056,7 +1033,7 @@ fn single_formatted_write() { fn bufreader_full_initialize() { struct OneByteReader; impl Read for OneByteReader { - fn read(&mut self, buf: &mut [u8]) -> crate::io::Result { + fn read(&mut self, buf: &mut [u8]) -> io::Result { if buf.len() > 0 { buf[0] = 0; Ok(1) @@ -1079,9 +1056,8 @@ fn bufreader_full_initialize() { /// This is a regression test for https://github.com/rust-lang/rust/issues/127584. #[test] fn bufwriter_aliasing() { - use crate::io::{BufWriter, Cursor}; let mut v = vec![0; 1024]; - let c = Cursor::new(&mut v); - let w = BufWriter::new(Box::new(c)); + let c = io::Cursor::new(&mut v); + let w = io::BufWriter::new(Box::new(c)); let _ = w.into_parts(); } diff --git a/library/std/src/io/copy/tests.rs b/library/alloctests/tests/io/copy.rs similarity index 75% rename from library/std/src/io/copy/tests.rs rename to library/alloctests/tests/io/copy.rs index 7bdba3a04416e..edab7a530cc01 100644 --- a/library/std/src/io/copy/tests.rs +++ b/library/alloctests/tests/io/copy.rs @@ -1,7 +1,7 @@ -use crate::cmp::{max, min}; -use crate::collections::VecDeque; -use crate::io; -use crate::io::*; +use alloc::collections::VecDeque; +use alloc::io; +use alloc::io::{DEFAULT_BUF_SIZE, *}; +use core::cmp::{max, min}; #[test] fn copy_copies() { @@ -65,7 +65,7 @@ fn copy_specializes_bufreader() { let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source)); let mut sink = Vec::new(); - assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); + assert_eq!(alloc::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); assert_eq!(source.as_slice(), sink.as_slice()); let buf_sz = 71 * 1024; @@ -73,7 +73,7 @@ fn copy_specializes_bufreader() { let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source)); let mut sink = WriteObserver { observed_buffer: 0 }; - assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); + assert_eq!(alloc::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); assert_eq!( sink.observed_buffer, buf_sz, "expected a large buffer to be provided to the writer" @@ -117,32 +117,3 @@ fn copy_specializes_from_slice() { assert_eq!(60 * 1024u64, io::copy(&mut source, &mut sink).unwrap()); assert_eq!(60 * 1024, sink.observed_buffer); } - -#[cfg(unix)] -mod io_benches { - use test::Bencher; - - use crate::fs::{File, OpenOptions}; - use crate::io::BufReader; - use crate::io::prelude::*; - - #[bench] - #[cfg_attr(target_os = "emscripten", ignore)] // no /dev - fn bench_copy_buf_reader(b: &mut Bencher) { - let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed"); - // use dyn to avoid specializations unrelated to readbuf - let dyn_in = &mut file_in as &mut dyn Read; - let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0)); - let mut writer = - OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed"); - - const BYTES: u64 = 1024 * 1024; - - b.bytes = BYTES; - - b.iter(|| { - reader.get_mut().set_limit(BYTES); - crate::io::copy(&mut reader, &mut writer).unwrap() - }); - } -} diff --git a/library/std/src/io/cursor/tests.rs b/library/alloctests/tests/io/cursor.rs similarity index 94% rename from library/std/src/io/cursor/tests.rs rename to library/alloctests/tests/io/cursor.rs index d7c203c297fe6..0ffdab2f2f396 100644 --- a/library/std/src/io/cursor/tests.rs +++ b/library/alloctests/tests/io/cursor.rs @@ -1,5 +1,5 @@ -use crate::io::prelude::*; -use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; +use alloc::io::prelude::*; +use alloc::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; #[test] fn test_vec_writer() { @@ -529,39 +529,3 @@ fn const_cursor() { const _: &&[u8] = CURSOR.get_ref(); const _: u64 = CURSOR.position(); } - -#[bench] -fn bench_write_vec(b: &mut test::Bencher) { - let slice = &[1; 128]; - - b.iter(|| { - let mut buf = b"some random data to overwrite".to_vec(); - let mut cursor = Cursor::new(&mut buf); - - let _ = cursor.write_all(slice); - test::black_box(&cursor); - }) -} - -#[bench] -fn bench_write_vec_vectored(b: &mut test::Bencher) { - let slices = [ - IoSlice::new(&[1; 128]), - IoSlice::new(&[2; 256]), - IoSlice::new(&[3; 512]), - IoSlice::new(&[4; 1024]), - IoSlice::new(&[5; 2048]), - IoSlice::new(&[6; 4096]), - IoSlice::new(&[7; 8192]), - IoSlice::new(&[8; 8192 * 2]), - ]; - - b.iter(|| { - let mut buf = b"some random data to overwrite".to_vec(); - let mut cursor = Cursor::new(&mut buf); - - let mut slices = slices; - let _ = cursor.write_all_vectored(&mut slices); - test::black_box(&cursor); - }) -} diff --git a/library/std/src/io/error/tests.rs b/library/alloctests/tests/io/error.rs similarity index 70% rename from library/std/src/io/error/tests.rs rename to library/alloctests/tests/io/error.rs index a8eef06381dae..57c55ebd78a28 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/alloctests/tests/io/error.rs @@ -1,6 +1,5 @@ -use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error}; -use crate::sys::io::{decode_error_kind, error_string}; -use crate::{assert_matches, error, fmt}; +use alloc::io::{Error, ErrorKind, const_error}; +use core::{error, fmt}; #[test] fn test_size() { @@ -10,14 +9,13 @@ fn test_size() { #[test] fn test_debug_error() { let code = 6; - let msg = error_string(code); - let kind = decode_error_kind(code); - let err = Error { - repr: Repr::new_custom(Box::new(Custom { - kind: ErrorKind::InvalidInput, - error: Box::new(Error { repr: super::Repr::new_os(code) }), - })), - }; + let err = Error::from_raw_os_error(code); + let mut msg = err.to_string(); + msg.truncate(msg.find('(').unwrap() - 1); + let kind = err.kind(); + + let err = Error::new(ErrorKind::InvalidInput, err); + let expected = format!( "Custom {{ \ kind: InvalidInput, \ @@ -30,6 +28,15 @@ fn test_debug_error() { code, kind, msg ); assert_eq!(format!("{err:?}"), expected); + + let err = Error::from(ErrorKind::AddrInUse); + assert_eq!(format!("{err:?}"), "Kind(AddrInUse)"); + + let err = Error::READ_EXACT_EOF; + assert_eq!( + format!("{err:?}"), + "Error { kind: UnexpectedEof, message: \"failed to fill whole buffer\" }" + ); } #[test] @@ -70,10 +77,6 @@ fn test_os_packing() { for code in -20..20 { let e = Error::from_raw_os_error(code); assert_eq!(e.raw_os_error(), Some(code)); - assert_matches!( - e.repr.data(), - ErrorData::Os(c) if c == code, - ); } } @@ -82,28 +85,18 @@ fn test_errorkind_packing() { assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound); assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied); assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized); - // Check that the innards look like what we want. - assert_matches!( - Error::from(ErrorKind::OutOfMemory).repr.data(), - ErrorData::Simple(ErrorKind::OutOfMemory), - ); } #[test] fn test_simple_message_packing() { - use super::ErrorKind::*; - use super::SimpleMessage; + use std::io::ErrorKind::*; macro_rules! check_simple_msg { ($err:expr, $kind:ident, $msg:literal) => {{ let e = &$err; // Check that the public api is right. assert_eq!(e.kind(), $kind); assert!(format!("{e:?}").contains($msg)); - // and we got what we expected - assert_matches!( - e.repr.data(), - ErrorData::SimpleMessage(SimpleMessage { kind: $kind, message: $msg }) - ); + assert!(format!("{e}").contains($msg)); }}; } @@ -126,19 +119,6 @@ impl fmt::Display for Bojji { } } -#[test] -fn test_custom_error_packing() { - use super::Custom; - let test = Error::new(ErrorKind::Uncategorized, Bojji(true)); - assert_matches!( - test.repr.data(), - ErrorData::Custom(Custom { - kind: ErrorKind::Uncategorized, - error, - }) if error.downcast_ref::().as_deref() == Some(&Bojji(true)), - ); -} - #[derive(Debug)] struct E; @@ -181,11 +161,9 @@ fn test_std_io_error_downcast() { assert_eq!(kind, io_error.kind()); // Case 5: simple message - const SIMPLE_MESSAGE: SimpleMessage = - SimpleMessage { kind: ErrorKind::Other, message: "simple message error test" }; - let io_error = Error::from_static_message(&SIMPLE_MESSAGE); + let io_error = const_error!(ErrorKind::Other, "simple message error test"); let io_error = io_error.downcast::().unwrap_err(); - assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind()); - assert_eq!(SIMPLE_MESSAGE.message, format!("{io_error}")); + assert_eq!(io_error.kind(), ErrorKind::Other); + assert_eq!(format!("{io_error}"), "simple message error test"); } diff --git a/library/std/src/io/tests.rs b/library/alloctests/tests/io/mod.rs similarity index 95% rename from library/std/src/io/tests.rs rename to library/alloctests/tests/io/mod.rs index a56359dae765b..734c08cd4aa9d 100644 --- a/library/std/src/io/tests.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,10 +1,14 @@ -use super::{BorrowedBuf, Cursor, SeekFrom, repeat}; -use crate::cmp::{self, min}; -use crate::io::{ - self, BufRead, BufReader, DEFAULT_BUF_SIZE, IoSlice, IoSliceMut, Read, Seek, Write, +use alloc::io::{ + self, BorrowedBuf, BufRead, BufReader, Cursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write, }; -use crate::mem::MaybeUninit; -use crate::ops::Deref; +use core::cmp::{self, min}; +use core::ops::Deref; + +mod buffered; +mod copy; +mod cursor; +mod error; +mod util; #[test] fn read_until() { @@ -273,7 +277,7 @@ fn chain_bufread() { #[test] fn chain_splitted_char() { let chain = b"\xc3".chain(b"\xa9".as_slice()); - assert_eq!(crate::io::read_to_string(chain).unwrap(), "é"); + assert_eq!(alloc::io::read_to_string(chain).unwrap(), "é"); let mut chain = b"\xc3".chain(b"\xa9\n".as_slice()); let mut buf = String::new(); @@ -357,16 +361,6 @@ fn chain_zero_length_read_is_not_eof() { assert_eq!("AB", s); } -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_read_to_end(b: &mut test::Bencher) { - b.iter(|| { - let mut lr = repeat(1).take(10000000); - let mut vec = Vec::with_capacity(1024); - super::default_read_to_end(&mut lr, &mut vec, None) - }); -} - #[test] fn seek_len() -> io::Result<()> { let mut c = Cursor::new(vec![0; 15]); @@ -528,11 +522,11 @@ fn take_seek_big_offsets() -> io::Result<()> { let inner = ExampleHugeRangeOfZeroes { position: 1 }; let mut take = inner.take(u64::MAX - 2); assert_eq!(take.seek(io::SeekFrom::Start(u64::MAX - 2))?, u64::MAX - 2); - assert_eq!(take.inner.position, u64::MAX - 1); + assert_eq!(take.get_ref().position, u64::MAX - 1); assert_eq!(take.seek(io::SeekFrom::Start(0))?, 0); - assert_eq!(take.inner.position, 1); + assert_eq!(take.get_ref().position, 1); assert_eq!(take.seek(io::SeekFrom::End(-1))?, u64::MAX - 3); - assert_eq!(take.inner.position, u64::MAX - 2); + assert_eq!(take.get_ref().position, u64::MAX - 2); Ok(()) } @@ -818,26 +812,6 @@ fn cursor_read_exact_eof() { assert_eq!(buf.filled(), b"123456"); } -#[bench] -fn bench_take_read(b: &mut test::Bencher) { - b.iter(|| { - let mut buf = [0; 64]; - - [255; 128].take(64).read(&mut buf).unwrap(); - }); -} - -#[bench] -fn bench_take_read_buf(b: &mut test::Bencher) { - b.iter(|| { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 64]; - - let mut buf: BorrowedBuf<'_> = buf.into(); - - [255; 128].take(64).read_buf(buf.unfilled()).unwrap(); - }); -} - // Issue #120603 #[test] #[should_panic] @@ -864,7 +838,7 @@ fn read_buf_full_read() { } } - assert_eq!(BufReader::new(FullRead).fill_buf().unwrap().len(), DEFAULT_BUF_SIZE); + assert_eq!(BufReader::new(FullRead).fill_buf().unwrap().len(), alloc::io::DEFAULT_BUF_SIZE); } struct DataAndErrorReader(&'static [u8]); diff --git a/library/std/src/io/util/tests.rs b/library/alloctests/tests/io/util.rs similarity index 98% rename from library/std/src/io/util/tests.rs rename to library/alloctests/tests/io/util.rs index d0f106d7af416..c5d8190c9ff1f 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/alloctests/tests/io/util.rs @@ -1,9 +1,9 @@ -use crate::fmt; -use crate::io::prelude::*; -use crate::io::{ +use alloc::io::prelude::*; +use alloc::io::{ BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Repeat, SeekFrom, Sink, empty, repeat, sink, }; -use crate::mem::MaybeUninit; +use core::fmt; +use core::mem::MaybeUninit; struct ErrorDisplay; diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 699a5010282b0..395fd4882a24f 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -1,6 +1,11 @@ +#![feature(alloc_io)] #![feature(allocator_api)] #![feature(binary_heap_pop_if)] +#![feature(buf_read_has_data_left)] +#![feature(can_vector)] #![feature(const_heap)] +#![feature(core_io_borrowed_buf)] +#![feature(cursor_split)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] #![feature(cow_is_borrowed)] @@ -22,6 +27,11 @@ #![feature(slice_range)] #![feature(slice_partial_sort_unstable)] #![feature(inplace_iteration)] +#![feature(io_const_error)] +#![feature(io_error_internals)] +#![feature(io_error_uncategorized)] +#![feature(io_internals)] +#![feature(io_slice_as_bytes)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(slice_partition_dedup)] @@ -33,6 +43,9 @@ #![feature(thin_box)] #![feature(drain_keep_rest)] #![feature(local_waker)] +#![feature(read_buf)] +#![feature(seek_io_take_position)] +#![feature(seek_stream_len)] #![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(string_replace_in_place)] @@ -41,6 +54,7 @@ #![feature(macro_metavar_expr_concat)] #![feature(vec_peek_mut)] #![feature(vec_try_remove)] +#![feature(write_all_vectored)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] @@ -62,6 +76,7 @@ mod const_fns; mod cow_str; mod fmt; mod heap; +mod io; mod linked_list; mod misc_tests; mod num; diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 9643d3fcae662..2b59194ed5760 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -45,7 +45,6 @@ use crate::ffi::OsString; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; use crate::sealed::Sealed; -use crate::sync::Arc; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, fs as fs_imp}; use crate::time::SystemTime; use crate::{error, fmt}; @@ -1542,58 +1541,6 @@ impl Seek for File { } } -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Read for Arc { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (&**self).read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - (&**self).read_vectored(bufs) - } - fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - (&**self).read_buf(cursor) - } - #[inline] - fn is_read_vectored(&self) -> bool { - (&**self).is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - (&**self).read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - (&**self).read_to_string(buf) - } -} -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Write for Arc { - fn write(&mut self, buf: &[u8]) -> io::Result { - (&**self).write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (&**self).write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - (&**self).is_write_vectored() - } - #[inline] - fn flush(&mut self) -> io::Result<()> { - (&**self).flush() - } -} -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Seek for Arc { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - (&**self).seek(pos) - } - fn stream_len(&mut self) -> io::Result { - (&**self).stream_len() - } - fn stream_position(&mut self) -> io::Result { - (&**self).stream_position() - } -} - impl Dir { /// Attempts to open a directory at `path` in read-only mode. /// diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 2b558efb8885e..3583cce5d147f 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,14 +1,6 @@ -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 super::{Read, Result, Write}; use crate::sys::io::{CopyState, kernel_copy}; -#[cfg(test)] -mod tests; - /// Copies the entire contents of a reader into a writer. /// /// This function will continuously read data from `reader` and then @@ -67,231 +59,7 @@ where match kernel_copy(reader, writer)? { CopyState::Ended(copied) => Ok(copied), CopyState::Fallback(copied) => { - generic_copy(reader, writer).map(|additional| copied + additional) - } - } -} - -/// 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(); + alloc::io::copy(reader, writer).map(|additional| copied + additional) } } } - -/// 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 = 0; - - loop { - let buf = self.buffer_mut(); - let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); - - unsafe { - // SAFETY: init is either 0 or the init_len from the previous iteration. - read_buf.set_init(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.init_len() - bytes_read; - 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 { - // All the bytes that were already in the buffer are initialized, - // treat them as such when the buffer is flushed. - init += buf.len(); - - 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<'_> = 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/error.rs b/library/std/src/io/error.rs index e6c6f7d766c02..56556ae8faa88 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -1,661 +1,18 @@ -#[cfg(test)] -mod tests; +//! OS-dependent public methods of `Error` -// On 64-bit platforms, `io::Error` may use a bit-packed representation to -// reduce size. However, this representation assumes that error codes are -// always 32-bit wide. -// -// This assumption is invalid on 64-bit UEFI, where error codes are 64-bit. -// Therefore, the packed representation is explicitly disabled for UEFI -// targets, and the unpacked representation must be used instead. -#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))] -mod repr_bitpacked; -#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))] -use repr_bitpacked::Repr; +#[cfg(not(test))] +use alloc::io::{Error, RawOsError}; -#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))] -mod repr_unpacked; -#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))] -use repr_unpacked::Repr; - -use crate::{error, fmt, result, sys}; - -/// A specialized [`Result`] type for I/O operations. -/// -/// This type is broadly used across [`std::io`] for any operation which may -/// produce an error. -/// -/// This type alias is generally used to avoid writing out [`io::Error`] directly and -/// is otherwise a direct mapping to [`Result`]. -/// -/// While usual Rust style is to import types directly, aliases of [`Result`] -/// often are not, to make it easier to distinguish between them. [`Result`] is -/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias -/// will generally use `io::Result` instead of shadowing the [prelude]'s import -/// of [`std::result::Result`][`Result`]. -/// -/// [`std::io`]: crate::io -/// [`io::Error`]: Error -/// [`Result`]: crate::result::Result -/// [prelude]: crate::prelude -/// -/// # Examples -/// -/// A convenience function that bubbles an `io::Result` to its caller: -/// -/// ``` -/// use std::io; -/// -/// fn get_string() -> io::Result { -/// let mut buffer = String::new(); -/// -/// io::stdin().read_line(&mut buffer)?; -/// -/// Ok(buffer) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(search_unbox)] -pub type Result = result::Result; - -/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and -/// associated traits. -/// -/// Errors mostly originate from the underlying OS, but custom instances of -/// `Error` can be created with crafted error messages and a particular value of -/// [`ErrorKind`]. -/// -/// [`Read`]: crate::io::Read -/// [`Write`]: crate::io::Write -/// [`Seek`]: crate::io::Seek -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Error { - repr: Repr, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.repr, f) - } -} - -/// Common errors constants for use in std -#[allow(dead_code)] -impl Error { - pub(crate) const INVALID_UTF8: Self = - const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); - - pub(crate) const READ_EXACT_EOF: Self = - const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); - - pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_error!( - ErrorKind::NotFound, - "the number of hardware threads is not known for the target platform", - ); - - pub(crate) const UNSUPPORTED_PLATFORM: Self = - const_error!(ErrorKind::Unsupported, "operation not supported on this platform"); - - pub(crate) const WRITE_ALL_EOF: Self = - const_error!(ErrorKind::WriteZero, "failed to write whole buffer"); - - pub(crate) const ZERO_TIMEOUT: Self = - const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); - - pub(crate) const NO_ADDRESSES: Self = - const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses"); -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From for Error { - /// Converts a [`alloc::ffi::NulError`] into a [`Error`]. - fn from(_: alloc::ffi::NulError) -> Error { - const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") - } -} - -#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")] -impl From for Error { - /// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`]. - /// - /// `TryReserveError` won't be available as the error `source()`, - /// but this may change in the future. - fn from(_: alloc::collections::TryReserveError) -> Error { - // ErrorData::Custom allocates, which isn't great for handling OOM errors. - ErrorKind::OutOfMemory.into() - } -} - -// Only derive debug in tests, to make sure it -// doesn't accidentally get printed. -#[cfg_attr(test, derive(Debug))] -enum ErrorData { - Os(RawOsError), - Simple(ErrorKind), - SimpleMessage(&'static SimpleMessage), - Custom(C), -} - -/// The type of raw OS error codes returned by [`Error::raw_os_error`]. -/// -/// This is an [`i32`] on all currently supported platforms, but platforms -/// added in the future (such as UEFI) may use a different primitive type like -/// [`usize`]. Use `as`or [`into`] conversions where applicable to ensure maximum -/// portability. -/// -/// [`into`]: Into::into -#[unstable(feature = "raw_os_error_ty", issue = "107792")] -pub type RawOsError = sys::io::RawOsError; - -// `#[repr(align(4))]` is probably redundant, it should have that value or -// higher already. We include it just because repr_bitpacked.rs's encoding -// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the -// alignment required by the struct, only increase it). -// -// If we add more variants to ErrorData, this can be increased to 8, but it -// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or -// whatever cfg we're using to enable the `repr_bitpacked` code, since only the -// that version needs the alignment, and 8 is higher than the alignment we'll -// have on 32 bit platforms. -// -// (For the sake of being explicit: the alignment requirement here only matters -// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't -// matter at all) -#[doc(hidden)] -#[unstable(feature = "io_const_error_internals", issue = "none")] -#[repr(align(4))] -#[derive(Debug)] -pub struct SimpleMessage { - pub kind: ErrorKind, - pub message: &'static str, -} - -/// Creates a new I/O error from a known kind of error and a string literal. -/// -/// Contrary to [`Error::new`], this macro does not allocate and can be used in -/// `const` contexts. -/// -/// # Example -/// ``` -/// #![feature(io_const_error)] -/// use std::io::{const_error, Error, ErrorKind}; -/// -/// const FAIL: Error = const_error!(ErrorKind::Unsupported, "tried something that never works"); -/// -/// fn not_here() -> Result<(), Error> { -/// Err(FAIL) -/// } -/// ``` -#[rustc_macro_transparency = "semiopaque"] -#[unstable(feature = "io_const_error", issue = "133448")] -#[allow_internal_unstable(hint_must_use, io_const_error_internals)] -pub macro const_error($kind:expr, $message:expr $(,)?) { - $crate::hint::must_use($crate::io::Error::from_static_message( - const { &$crate::io::SimpleMessage { kind: $kind, message: $message } }, - )) -} - -// As with `SimpleMessage`: `#[repr(align(4))]` here is just because -// repr_bitpacked's encoding requires it. In practice it almost certainly be -// already be this high or higher. -#[derive(Debug)] -#[repr(align(4))] -struct Custom { - kind: ErrorKind, - error: Box, -} - -/// A list specifying general categories of I/O error. -/// -/// This list is intended to grow over time and it is not recommended to -/// exhaustively match against it. -/// -/// It is used with the [`io::Error`] type. -/// -/// [`io::Error`]: Error -/// -/// # Handling errors and matching on `ErrorKind` -/// -/// In application code, use `match` for the `ErrorKind` values you are -/// expecting; use `_` to match "all other errors". -/// -/// In comprehensive and thorough tests that want to verify that a test doesn't -/// return any known incorrect error kind, you may want to cut-and-paste the -/// current full list of errors from here into your test code, and then match -/// `_` as the correct case. This seems counterintuitive, but it will make your -/// tests more robust. In particular, if you want to verify that your code does -/// produce an unrecognized error kind, the robust solution is to check for all -/// the recognized error kinds and fail in those cases. -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "io_errorkind")] -#[allow(deprecated)] -#[non_exhaustive] -pub enum ErrorKind { - /// An entity was not found, often a file. - #[stable(feature = "rust1", since = "1.0.0")] - NotFound, - /// The operation lacked the necessary privileges to complete. - #[stable(feature = "rust1", since = "1.0.0")] - PermissionDenied, - /// The connection was refused by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionRefused, - /// The connection was reset by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionReset, - /// The remote host is not reachable. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - HostUnreachable, - /// The network containing the remote host is not reachable. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - NetworkUnreachable, - /// The connection was aborted (terminated) by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionAborted, - /// The network operation failed because it was not connected yet. - #[stable(feature = "rust1", since = "1.0.0")] - NotConnected, - /// A socket address could not be bound because the address is already in - /// use elsewhere. - #[stable(feature = "rust1", since = "1.0.0")] - AddrInUse, - /// A nonexistent interface was requested or the requested address was not - /// local. - #[stable(feature = "rust1", since = "1.0.0")] - AddrNotAvailable, - /// The system's networking is down. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - NetworkDown, - /// The operation failed because a pipe was closed. - #[stable(feature = "rust1", since = "1.0.0")] - BrokenPipe, - /// An entity already exists, often a file. - #[stable(feature = "rust1", since = "1.0.0")] - AlreadyExists, - /// The operation needs to block to complete, but the blocking operation was - /// requested to not occur. - #[stable(feature = "rust1", since = "1.0.0")] - WouldBlock, - /// A filesystem object is, unexpectedly, not a directory. - /// - /// For example, a filesystem path was specified where one of the intermediate directory - /// components was, in fact, a plain file. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - NotADirectory, - /// The filesystem object is, unexpectedly, a directory. - /// - /// A directory was specified when a non-directory was expected. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - IsADirectory, - /// A non-empty directory was specified where an empty directory was expected. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - DirectoryNotEmpty, - /// The filesystem or storage medium is read-only, but a write operation was attempted. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - ReadOnlyFilesystem, - /// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links. - /// - /// There was a loop (or excessively long chain) resolving a filesystem object - /// or file IO object. - /// - /// On Unix this is usually the result of a symbolic link loop; or, of exceeding the - /// system-specific limit on the depth of symlink traversal. - #[unstable(feature = "io_error_more", issue = "86442")] - FilesystemLoop, - /// Stale network file handle. - /// - /// With some network filesystems, notably NFS, an open file (or directory) can be invalidated - /// by problems with the network or server. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - StaleNetworkFileHandle, - /// A parameter was incorrect. - #[stable(feature = "rust1", since = "1.0.0")] - InvalidInput, - /// Data not valid for the operation were encountered. - /// - /// Unlike [`InvalidInput`], this typically means that the operation - /// parameters were valid, however the error was caused by malformed - /// input data. - /// - /// For example, a function that reads a file into a string will error with - /// `InvalidData` if the file's contents are not valid UTF-8. - /// - /// [`InvalidInput`]: ErrorKind::InvalidInput - #[stable(feature = "io_invalid_data", since = "1.2.0")] - InvalidData, - /// The I/O operation's timeout expired, causing it to be canceled. - #[stable(feature = "rust1", since = "1.0.0")] - TimedOut, - /// An error returned when an operation could not be completed because a - /// call to [`write`] returned [`Ok(0)`]. - /// - /// This typically means that an operation could only succeed if it wrote a - /// particular number of bytes but only a smaller number of bytes could be - /// written. - /// - /// [`write`]: crate::io::Write::write - /// [`Ok(0)`]: Ok - #[stable(feature = "rust1", since = "1.0.0")] - WriteZero, - /// The underlying storage (typically, a filesystem) is full. - /// - /// This does not include out of quota errors. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - StorageFull, - /// Seek on unseekable file. - /// - /// Seeking was attempted on an open file handle which is not suitable for seeking - for - /// example, on Unix, a named pipe opened with `File::open`. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - NotSeekable, - /// Filesystem quota or some other kind of quota was exceeded. - #[stable(feature = "io_error_quota_exceeded", since = "1.85.0")] - QuotaExceeded, - /// File larger than allowed or supported. - /// - /// This might arise from a hard limit of the underlying filesystem or file access API, or from - /// an administratively imposed resource limitation. Simple disk full, and out of quota, have - /// their own errors. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - FileTooLarge, - /// Resource is busy. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - ResourceBusy, - /// Executable file is busy. - /// - /// An attempt was made to write to a file which is also in use as a running program. (Not all - /// operating systems detect this situation.) - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - ExecutableFileBusy, - /// Deadlock (avoided). - /// - /// A file locking operation would result in deadlock. This situation is typically detected, if - /// at all, on a best-effort basis. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - Deadlock, - /// Cross-device or cross-filesystem (hard) link or rename. - #[stable(feature = "io_error_crosses_devices", since = "1.85.0")] - CrossesDevices, - /// Too many (hard) links to the same filesystem object. - /// - /// The filesystem does not support making so many hardlinks to the same file. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - TooManyLinks, - /// A filename was invalid. - /// - /// This error can also occur if a length limit for a name was exceeded. - #[stable(feature = "io_error_invalid_filename", since = "1.87.0")] - InvalidFilename, - /// Program argument list too long. - /// - /// When trying to run an external program, a system or process limit on the size of the - /// arguments would have been exceeded. - #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] - ArgumentListTooLong, - /// This operation was interrupted. - /// - /// Interrupted operations can typically be retried. - #[stable(feature = "rust1", since = "1.0.0")] - Interrupted, - - /// This operation is unsupported on this platform. - /// - /// This means that the operation can never succeed. - #[stable(feature = "unsupported_error", since = "1.53.0")] - Unsupported, - - // ErrorKinds which are primarily categorisations for OS error - // codes should be added above. - // - /// An error returned when an operation could not be completed because an - /// "end of file" was reached prematurely. - /// - /// This typically means that an operation could only succeed if it read a - /// particular number of bytes but only a smaller number of bytes could be - /// read. - #[stable(feature = "read_exact", since = "1.6.0")] - UnexpectedEof, - - /// An operation could not be completed, because it failed - /// to allocate enough memory. - #[stable(feature = "out_of_memory_error", since = "1.54.0")] - OutOfMemory, - - /// The operation was partially successful and needs to be checked - /// later on due to not blocking. - #[unstable(feature = "io_error_inprogress", issue = "130840")] - InProgress, - - // "Unusual" error kinds which do not correspond simply to (sets - // of) OS error codes, should be added just above this comment. - // `Other` and `Uncategorized` should remain at the end: - // - /// A custom error that does not fall under any other I/O error kind. - /// - /// This can be used to construct your own [`Error`]s that do not match any - /// [`ErrorKind`]. - /// - /// This [`ErrorKind`] is not used by the standard library. - /// - /// Errors from the standard library that do not fall under any of the I/O - /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern. - /// New [`ErrorKind`]s might be added in the future for some of those. - #[stable(feature = "rust1", since = "1.0.0")] - Other, - - /// Any I/O error from the standard library that's not part of this list. - /// - /// Errors that are `Uncategorized` now may move to a different or a new - /// [`ErrorKind`] variant in the future. It is not recommended to match - /// an error against `Uncategorized`; use a wildcard match (`_`) instead. - #[unstable(feature = "io_error_uncategorized", issue = "none")] - #[doc(hidden)] - Uncategorized, -} - -impl ErrorKind { - pub(crate) fn as_str(&self) -> &'static str { - use ErrorKind::*; - match *self { - // tidy-alphabetical-start - AddrInUse => "address in use", - AddrNotAvailable => "address not available", - AlreadyExists => "entity already exists", - ArgumentListTooLong => "argument list too long", - BrokenPipe => "broken pipe", - ConnectionAborted => "connection aborted", - ConnectionRefused => "connection refused", - ConnectionReset => "connection reset", - CrossesDevices => "cross-device link or rename", - Deadlock => "deadlock", - DirectoryNotEmpty => "directory not empty", - ExecutableFileBusy => "executable file busy", - FileTooLarge => "file too large", - FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", - HostUnreachable => "host unreachable", - InProgress => "in progress", - Interrupted => "operation interrupted", - InvalidData => "invalid data", - InvalidFilename => "invalid filename", - InvalidInput => "invalid input parameter", - IsADirectory => "is a directory", - NetworkDown => "network down", - NetworkUnreachable => "network unreachable", - NotADirectory => "not a directory", - NotConnected => "not connected", - NotFound => "entity not found", - NotSeekable => "seek on unseekable file", - Other => "other error", - OutOfMemory => "out of memory", - PermissionDenied => "permission denied", - QuotaExceeded => "quota exceeded", - ReadOnlyFilesystem => "read-only filesystem or storage medium", - ResourceBusy => "resource busy", - StaleNetworkFileHandle => "stale network file handle", - StorageFull => "no storage space", - TimedOut => "timed out", - TooManyLinks => "too many links", - Uncategorized => "uncategorized error", - UnexpectedEof => "unexpected end of file", - Unsupported => "unsupported", - WouldBlock => "operation would block", - WriteZero => "write zero", - // tidy-alphabetical-end - } - } -} - -#[stable(feature = "io_errorkind_display", since = "1.60.0")] -impl fmt::Display for ErrorKind { - /// Shows a human-readable description of the `ErrorKind`. - /// - /// This is similar to `impl Display for Error`, but doesn't require first converting to Error. - /// - /// # Examples - /// ``` - /// use std::io::ErrorKind; - /// assert_eq!("entity not found", ErrorKind::NotFound.to_string()); - /// ``` - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.write_str(self.as_str()) - } -} - -/// Intended for use for errors not exposed to the user, where allocating onto -/// the heap (for normal construction via Error::new) is too costly. -#[stable(feature = "io_error_from_errorkind", since = "1.14.0")] -impl From for Error { - /// Converts an [`ErrorKind`] into an [`Error`]. - /// - /// This conversion creates a new error with a simple representation of error kind. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// let not_found = ErrorKind::NotFound; - /// let error = Error::from(not_found); - /// assert_eq!("entity not found", format!("{error}")); - /// ``` - #[inline] - fn from(kind: ErrorKind) -> Error { - Error { repr: Repr::new_simple(kind) } - } -} +const _: () = { + let _ = crate::sys::io::error_string; + let _ = crate::sys::io::decode_error_kind; + let _ = crate::sys::io::is_interrupted; +}; +// FIXME: for some reason, enabling these in `test` config makes them defined twice, +// but it does not seem to be the case with other incoherent items. +#[cfg(not(test))] impl Error { - /// Creates a new I/O error from a known kind of error as well as an - /// arbitrary error payload. - /// - /// This function is used to generically create I/O errors which do not - /// originate from the OS itself. The `error` argument is an arbitrary - /// payload which will be contained in this [`Error`]. - /// - /// Note that this function allocates memory on the heap. - /// If no extra payload is required, use the `From` conversion from - /// `ErrorKind`. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// // errors can be created from strings - /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); - /// - /// // errors can also be created from other errors - /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); - /// - /// // creating an error without payload (and without memory allocation) - /// let eof_error = Error::from(ErrorKind::UnexpectedEof); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")] - #[inline(never)] - pub fn new(kind: ErrorKind, error: E) -> Error - where - E: Into>, - { - Self::_new(kind, error.into()) - } - - /// Creates a new I/O error from an arbitrary error payload. - /// - /// This function is used to generically create I/O errors which do not - /// originate from the OS itself. It is a shortcut for [`Error::new`] - /// with [`ErrorKind::Other`]. - /// - /// # Examples - /// - /// ``` - /// use std::io::Error; - /// - /// // errors can be created from strings - /// let custom_error = Error::other("oh no!"); - /// - /// // errors can also be created from other errors - /// let custom_error2 = Error::other(custom_error); - /// ``` - #[stable(feature = "io_error_other", since = "1.74.0")] - pub fn other(error: E) -> Error - where - E: Into>, - { - Self::_new(ErrorKind::Other, error.into()) - } - - fn _new(kind: ErrorKind, error: Box) -> Error { - Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) } - } - - /// Creates a new I/O error from a known kind of error as well as a constant - /// message. - /// - /// This function does not allocate. - /// - /// You should not use this directly, and instead use the `const_error!` - /// macro: `io::const_error!(ErrorKind::Something, "some_message")`. - /// - /// This function should maybe change to `from_static_message(kind: ErrorKind)` in the future, when const generics allow that. - #[inline] - #[doc(hidden)] - #[unstable(feature = "io_const_error_internals", issue = "none")] - pub const fn from_static_message(msg: &'static SimpleMessage) -> Error { - Self { repr: Repr::new_simple_message(msg) } - } - - /// Returns an error representing the last OS error which occurred. - /// - /// This function reads the value of `errno` for the target platform (e.g. - /// `GetLastError` on Windows) and will return a corresponding instance of - /// [`Error`] for the error code. - /// - /// This should be called immediately after a call to a platform function, - /// otherwise the state of the error value is indeterminate. In particular, - /// other standard library functions may call platform functions that may - /// (or may not) reset the error value even if they succeed. - /// - /// # Examples - /// - /// ``` - /// use std::io::Error; - /// - /// let os_error = Error::last_os_error(); - /// println!("last OS error: {os_error:?}"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[doc(alias = "GetLastError")] - #[doc(alias = "errno")] - #[must_use] - #[inline] - pub fn last_os_error() -> Error { - Error::from_raw_os_error(sys::io::errno()) - } - /// Creates a new instance of an [`Error`] from a particular OS error code. /// /// # Examples @@ -684,19 +41,24 @@ impl Error { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] + #[rustc_allow_incoherent_impl] pub fn from_raw_os_error(code: RawOsError) -> Error { - Error { repr: Repr::new_os(code) } + Error::_from_raw_os_error( + code, + &alloc::io::OsFunctions { + error_string: crate::sys::io::error_string, + decode_error_kind: crate::sys::io::decode_error_kind, + is_interrupted: crate::sys::io::is_interrupted, + }, + ) } /// Returns the OS error that this error represents (if any). /// - /// If this [`Error`] was constructed via [`last_os_error`] or - /// [`from_raw_os_error`], then this function will return [`Some`], otherwise + /// If this [`Error`] was constructed via `last_os_error` or + /// `from_raw_os_error`, then this function will return [`Some`], otherwise /// it will return [`None`]. /// - /// [`last_os_error`]: Error::last_os_error - /// [`from_raw_os_error`]: Error::from_raw_os_error - /// /// # Examples /// /// ``` @@ -720,366 +82,37 @@ impl Error { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] + #[rustc_allow_incoherent_impl] pub fn raw_os_error(&self) -> Option { - match self.repr.data() { - ErrorData::Os(i) => Some(i), - ErrorData::Custom(..) => None, - ErrorData::Simple(..) => None, - ErrorData::SimpleMessage(..) => None, - } - } - - /// Returns a reference to the inner error wrapped by this error (if any). - /// - /// If this [`Error`] was constructed via [`new`] then this function will - /// return [`Some`], otherwise it will return [`None`]. - /// - /// [`new`]: Error::new - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: &Error) { - /// if let Some(inner_err) = err.get_ref() { - /// println!("Inner error: {inner_err:?}"); - /// } else { - /// println!("No inner error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(&Error::last_os_error()); - /// // Will print "Inner error: ...". - /// print_error(&Error::new(ErrorKind::Other, "oh no!")); - /// } - /// ``` - #[stable(feature = "io_error_inner", since = "1.3.0")] - #[must_use] - #[inline] - pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> { - match self.repr.data() { - ErrorData::Os(..) => None, - ErrorData::Simple(..) => None, - ErrorData::SimpleMessage(..) => None, - ErrorData::Custom(c) => Some(&*c.error), - } - } - - /// Returns a mutable reference to the inner error wrapped by this error - /// (if any). - /// - /// If this [`Error`] was constructed via [`new`] then this function will - /// return [`Some`], otherwise it will return [`None`]. - /// - /// [`new`]: Error::new - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// use std::{error, fmt}; - /// use std::fmt::Display; - /// - /// #[derive(Debug)] - /// struct MyError { - /// v: String, - /// } - /// - /// impl MyError { - /// fn new() -> MyError { - /// MyError { - /// v: "oh no!".to_string() - /// } - /// } - /// - /// fn change_message(&mut self, new_message: &str) { - /// self.v = new_message.to_string(); - /// } - /// } - /// - /// impl error::Error for MyError {} - /// - /// impl Display for MyError { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f, "MyError: {}", self.v) - /// } - /// } - /// - /// fn change_error(mut err: Error) -> Error { - /// if let Some(inner_err) = err.get_mut() { - /// inner_err.downcast_mut::().unwrap().change_message("I've been changed!"); - /// } - /// err - /// } - /// - /// fn print_error(err: &Error) { - /// if let Some(inner_err) = err.get_ref() { - /// println!("Inner error: {inner_err}"); - /// } else { - /// println!("No inner error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(&change_error(Error::last_os_error())); - /// // Will print "Inner error: ...". - /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new()))); - /// } - /// ``` - #[stable(feature = "io_error_inner", since = "1.3.0")] - #[must_use] - #[inline] - pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> { - match self.repr.data_mut() { - ErrorData::Os(..) => None, - ErrorData::Simple(..) => None, - ErrorData::SimpleMessage(..) => None, - ErrorData::Custom(c) => Some(&mut *c.error), - } + self._raw_os_error() } - /// Consumes the `Error`, returning its inner error (if any). - /// - /// If this [`Error`] was constructed via [`new`] or [`other`], - /// then this function will return [`Some`], - /// otherwise it will return [`None`]. - /// - /// [`new`]: Error::new - /// [`other`]: Error::other - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: Error) { - /// if let Some(inner_err) = err.into_inner() { - /// println!("Inner error: {inner_err}"); - /// } else { - /// println!("No inner error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(Error::last_os_error()); - /// // Will print "Inner error: ...". - /// print_error(Error::new(ErrorKind::Other, "oh no!")); - /// } - /// ``` - #[stable(feature = "io_error_inner", since = "1.3.0")] - #[must_use = "`self` will be dropped if the result is not used"] - #[inline] - pub fn into_inner(self) -> Option> { - match self.repr.into_data() { - ErrorData::Os(..) => None, - ErrorData::Simple(..) => None, - ErrorData::SimpleMessage(..) => None, - ErrorData::Custom(c) => Some(c.error), - } - } - - /// Attempts to downcast the custom boxed error to `E`. - /// - /// If this [`Error`] contains a custom boxed error, - /// then it would attempt downcasting on the boxed error, - /// otherwise it will return [`Err`]. - /// - /// If the custom boxed error has the same type as `E`, it will return [`Ok`], - /// otherwise it will also return [`Err`]. - /// - /// This method is meant to be a convenience routine for calling - /// `Box::downcast` on the custom boxed error, returned by - /// [`Error::into_inner`]. - /// - /// - /// # Examples - /// - /// ``` - /// use std::fmt; - /// use std::io; - /// use std::error::Error; - /// - /// #[derive(Debug)] - /// enum E { - /// Io(io::Error), - /// SomeOtherVariant, - /// } - /// - /// impl fmt::Display for E { - /// // ... - /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// # todo!() - /// # } - /// } - /// impl Error for E {} - /// - /// impl From for E { - /// fn from(err: io::Error) -> E { - /// err.downcast::() - /// .unwrap_or_else(E::Io) - /// } - /// } - /// - /// impl From for io::Error { - /// fn from(err: E) -> io::Error { - /// match err { - /// E::Io(io_error) => io_error, - /// e => io::Error::new(io::ErrorKind::Other, e), - /// } - /// } - /// } - /// - /// # fn main() { - /// let e = E::SomeOtherVariant; - /// // Convert it to an io::Error - /// let io_error = io::Error::from(e); - /// // Cast it back to the original variant - /// let e = E::from(io_error); - /// assert!(matches!(e, E::SomeOtherVariant)); - /// - /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists); - /// // Convert it to E - /// let e = E::from(io_error); - /// // Cast it back to the original variant - /// let io_error = io::Error::from(e); - /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists); - /// assert!(io_error.get_ref().is_none()); - /// assert!(io_error.raw_os_error().is_none()); - /// # } - /// ``` - #[stable(feature = "io_error_downcast", since = "1.79.0")] - pub fn downcast(self) -> result::Result - where - E: error::Error + Send + Sync + 'static, - { - if let ErrorData::Custom(c) = self.repr.data() - && c.error.is::() - { - if let ErrorData::Custom(b) = self.repr.into_data() - && let Ok(err) = b.error.downcast::() - { - Ok(*err) - } else { - // Safety: We have just checked that the condition is true - unsafe { crate::hint::unreachable_unchecked() } - } - } else { - Err(self) - } - } - - /// Returns the corresponding [`ErrorKind`] for this error. + /// Returns an error representing the last OS error which occurred. /// - /// This may be a value set by Rust code constructing custom `io::Error`s, - /// or if this `io::Error` was sourced from the operating system, - /// it will be a value inferred from the system's error encoding. - /// See [`last_os_error`] for more details. + /// This function reads the value of `errno` for the target platform (e.g. + /// `GetLastError` on Windows) and will return a corresponding instance of + /// [`Error`] for the error code. /// - /// [`last_os_error`]: Error::last_os_error + /// This should be called immediately after a call to a platform function, + /// otherwise the state of the error value is indeterminate. In particular, + /// other standard library functions may call platform functions that may + /// (or may not) reset the error value even if they succeed. /// /// # Examples /// /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: Error) { - /// println!("{:?}", err.kind()); - /// } + /// use std::io::Error; /// - /// fn main() { - /// // As no error has (visibly) occurred, this may print anything! - /// // It likely prints a placeholder for unidentified (non-)errors. - /// print_error(Error::last_os_error()); - /// // Will print "AddrInUse". - /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); - /// } + /// let os_error = Error::last_os_error(); + /// println!("last OS error: {os_error:?}"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "GetLastError")] + #[doc(alias = "errno")] #[must_use] #[inline] - pub fn kind(&self) -> ErrorKind { - match self.repr.data() { - ErrorData::Os(code) => sys::io::decode_error_kind(code), - ErrorData::Custom(c) => c.kind, - ErrorData::Simple(kind) => kind, - ErrorData::SimpleMessage(m) => m.kind, - } - } - - #[inline] - pub(crate) fn is_interrupted(&self) -> bool { - match self.repr.data() { - ErrorData::Os(code) => sys::io::is_interrupted(code), - ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted, - ErrorData::Simple(kind) => kind == ErrorKind::Interrupted, - ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted, - } - } -} - -impl fmt::Debug for Repr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.data() { - ErrorData::Os(code) => fmt - .debug_struct("Os") - .field("code", &code) - .field("kind", &sys::io::decode_error_kind(code)) - .field("message", &sys::io::error_string(code)) - .finish(), - ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt), - ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), - ErrorData::SimpleMessage(msg) => fmt - .debug_struct("Error") - .field("kind", &msg.kind) - .field("message", &msg.message) - .finish(), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.repr.data() { - ErrorData::Os(code) => { - let detail = sys::io::error_string(code); - write!(fmt, "{detail} (os error {code})") - } - ErrorData::Custom(ref c) => c.error.fmt(fmt), - ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()), - ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for Error { - #[allow(deprecated)] - fn cause(&self) -> Option<&dyn error::Error> { - match self.repr.data() { - ErrorData::Os(..) => None, - ErrorData::Simple(..) => None, - ErrorData::SimpleMessage(..) => None, - ErrorData::Custom(c) => c.error.cause(), - } - } - - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self.repr.data() { - ErrorData::Os(..) => None, - ErrorData::Simple(..) => None, - ErrorData::SimpleMessage(..) => None, - ErrorData::Custom(c) => c.error.source(), - } + #[rustc_allow_incoherent_impl] + pub fn last_os_error() -> Error { + Error::from_raw_os_error(crate::sys::io::errno()) } } - -fn _assert_error_is_sync_send() { - fn _is_sync_send() {} - _is_sync_send::(); -} diff --git a/library/std/src/io/impls/tests.rs b/library/std/src/io/impls/tests.rs deleted file mode 100644 index d1cd84a67ada5..0000000000000 --- a/library/std/src/io/impls/tests.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::io::prelude::*; - -#[bench] -fn bench_read_slice(b: &mut test::Bencher) { - let buf = [5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) -} - -#[bench] -fn bench_write_slice(b: &mut test::Bencher) { - let mut buf = [0; 1024]; - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) -} - -#[bench] -fn bench_read_vec(b: &mut test::Bencher) { - let buf = vec![5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) -} - -#[bench] -fn bench_write_vec(b: &mut test::Bencher) { - let mut buf = Vec::with_capacity(1024); - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) -} diff --git a/library/std/src/io/io_benches.rs b/library/std/src/io/io_benches.rs new file mode 100644 index 0000000000000..529b47066d387 --- /dev/null +++ b/library/std/src/io/io_benches.rs @@ -0,0 +1,171 @@ +use crate::io::prelude::*; +use crate::io::{self, BorrowedBuf, IoSlice}; +use crate::mem::MaybeUninit; + +#[bench] +fn bench_read_slice(b: &mut test::Bencher) { + let buf = [5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in 0..8 { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) +} + +#[bench] +fn bench_write_slice(b: &mut test::Bencher) { + let mut buf = [0; 1024]; + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in 0..8 { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) +} + +#[bench] +fn bench_read_vec(b: &mut test::Bencher) { + let buf = vec![5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in 0..8 { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) +} + +#[bench] +fn bench_write_vec(b: &mut test::Bencher) { + let mut buf = Vec::with_capacity(1024); + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in 0..8 { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) +} + +#[cfg(unix)] +#[cfg_attr(target_os = "emscripten", ignore)] // no /dev +#[bench] +fn bench_copy_buf_reader(b: &mut test::Bencher) { + use crate::fs; + + let mut file_in = fs::File::open("/dev/zero").expect("opening /dev/zero failed"); + // use dyn to avoid specializations unrelated to readbuf + let dyn_in = &mut file_in as &mut dyn Read; + let mut reader = io::BufReader::with_capacity(256 * 1024, dyn_in.take(0)); + let mut writer = + fs::OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed"); + + const BYTES: u64 = 1024 * 1024; + + b.bytes = BYTES; + + b.iter(|| { + reader.get_mut().set_limit(BYTES); + io::copy(&mut reader, &mut writer).unwrap() + }); +} + +#[bench] +fn bench_write_cursor_vec(b: &mut test::Bencher) { + let slice = &[1; 128]; + + b.iter(|| { + let mut buf = b"some random data to overwrite".to_vec(); + let mut cursor = io::Cursor::new(&mut buf); + + let _ = cursor.write_all(slice); + test::black_box(&cursor); + }) +} + +#[bench] +fn bench_write_cursor_vec_vectored(b: &mut test::Bencher) { + let slices = [ + IoSlice::new(&[1; 128]), + IoSlice::new(&[2; 256]), + IoSlice::new(&[3; 512]), + IoSlice::new(&[4; 1024]), + IoSlice::new(&[5; 2048]), + IoSlice::new(&[6; 4096]), + IoSlice::new(&[7; 8192]), + IoSlice::new(&[8; 8192 * 2]), + ]; + + b.iter(|| { + let mut buf = b"some random data to overwrite".to_vec(); + let mut cursor = io::Cursor::new(&mut buf); + + let mut slices = slices; + let _ = cursor.write_all_vectored(&mut slices); + test::black_box(&cursor); + }) +} + +#[bench] +fn bench_take_read(b: &mut test::Bencher) { + b.iter(|| { + let mut buf = [0; 64]; + + [255; 128].take(64).read(&mut buf).unwrap(); + }); +} + +#[bench] +fn bench_take_read_buf(b: &mut test::Bencher) { + b.iter(|| { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 64]; + + let mut buf: BorrowedBuf<'_> = buf.into(); + + [255; 128].take(64).read_buf(buf.unfilled()).unwrap(); + }); +} + +#[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... +fn bench_read_to_end(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = io::repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + io::default_read_to_end(&mut lr, &mut vec, None) + }); +} + +#[bench] +fn bench_buffered_reader(b: &mut test::Bencher) { + b.iter(|| io::BufReader::new(io::empty())); +} + +#[bench] +fn bench_buffered_reader_small_reads(b: &mut test::Bencher) { + let data = (0..u8::MAX).cycle().take(1024 * 4).collect::>(); + b.iter(|| { + let mut reader = io::BufReader::new(&data[..]); + let mut buf = [0u8; 4]; + for _ in 0..1024 { + reader.read_exact(&mut buf).unwrap(); + core::hint::black_box(&buf); + } + }); +} + +#[bench] +fn bench_buffered_writer(b: &mut test::Bencher) { + b.iter(|| io::BufWriter::new(io::sink())); +} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index cba578cd3a6fa..92b2c88171ae4 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -294,22 +294,26 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(test)] -mod tests; - -#[unstable(feature = "read_buf", issue = "78485")] -pub use core::io::{BorrowedBuf, BorrowedCursor}; -use core::slice::memchr; - -#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] -pub use self::buffered::WriterPanicked; #[unstable(feature = "raw_os_error_ty", issue = "107792")] -pub use self::error::RawOsError; +pub use alloc::io::RawOsError; #[doc(hidden)] #[unstable(feature = "io_const_error_internals", issue = "none")] -pub use self::error::SimpleMessage; +pub use alloc::io::SimpleMessage; +#[stable(feature = "bufwriter_into_parts", since = "1.56.0")] +pub use alloc::io::WriterPanicked; #[unstable(feature = "io_const_error", issue = "133448")] -pub use self::error::const_error; +pub use alloc::io::const_error; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc::io::{ + BufRead, BufReader, BufWriter, Bytes, Chain, Cursor, Empty, Error, ErrorKind, IntoInnerError, + LineWriter, Lines, Read, Repeat, Result, Seek, SeekFrom, Sink, Split, Take, Write, empty, + prelude, read_to_string, repeat, sink, +}; +#[stable(feature = "iovec", since = "1.36.0")] +pub use alloc::io::{IoSlice, IoSliceMut}; +#[unstable(feature = "read_buf", issue = "78485")] +pub use core::io::{BorrowedBuf, BorrowedCursor}; + #[stable(feature = "anonymous_pipe", since = "1.87.0")] pub use self::pipe::{PipeReader, PipeWriter, pipe}; #[stable(feature = "is_terminal", since = "1.70.0")] @@ -323,3087 +327,21 @@ 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, - cursor::Cursor, - error::{Error, ErrorKind, Result}, stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout}, - util::{Empty, Repeat, Sink, empty, repeat, sink}, }; -use crate::mem::{MaybeUninit, take}; -use crate::ops::{Deref, DerefMut}; -use crate::{cmp, fmt, slice, str, sys}; -mod buffered; pub(crate) mod copy; -mod cursor; mod error; -mod impls; mod pipe; -pub mod prelude; mod stdio; -mod util; -const DEFAULT_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; +pub(crate) use alloc::io::{ + SpecReadByte, default_read_buf, default_read_to_end, default_read_to_string, + default_read_vectored, default_write_vectored, stream_len_default, +}; pub(crate) use stdio::cleanup; -struct Guard<'a> { - buf: &'a mut Vec, - len: usize, -} - -impl Drop for Guard<'_> { - fn drop(&mut self) { - unsafe { - self.buf.set_len(self.len); - } - } -} - -// Several `read_to_string` and `read_line` methods in the standard library will -// append data into a `String` buffer, but we need to be pretty careful when -// doing this. The implementation will just call `.as_mut_vec()` and then -// delegate to a byte-oriented reading method, but we must ensure that when -// returning we never leave `buf` in a state such that it contains invalid UTF-8 -// in its bounds. -// -// To this end, we use an RAII guard (to protect against panics) which updates -// the length of the string when it is dropped. This guard initially truncates -// the string to the prior length and only after we've validated that the -// new contents are valid UTF-8 do we allow it to set a longer length. -// -// The unsafety in this function is twofold: -// -// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8 -// checks. -// 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. -pub(crate) unsafe fn append_to_string(buf: &mut String, f: F) -> Result -where - F: FnOnce(&mut Vec) -> Result, -{ - let mut g = Guard { len: buf.len(), buf: unsafe { buf.as_mut_vec() } }; - let ret = f(g.buf); - - // SAFETY: the caller promises to only append data to `buf` - let appended = unsafe { g.buf.get_unchecked(g.len..) }; - if str::from_utf8(appended).is_err() { - ret.and_then(|_| Err(Error::INVALID_UTF8)) - } else { - g.len = g.buf.len(); - ret - } -} - -// Here we must serve many masters with conflicting goals: -// -// - avoid allocating unless necessary -// - avoid overallocating if we know the exact size (#89165) -// - avoid passing large buffers to readers that always initialize the free capacity if they perform short reads (#23815, #23820) -// - pass large buffers to readers that do not initialize the spare capacity. this can amortize per-call overheads -// - and finally pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems -// at the same time, i.e. small reads suffer from syscall overhead, all reads incur costs proportional to buffer size (#110650) -// -pub(crate) fn default_read_to_end( - r: &mut R, - buf: &mut Vec, - size_hint: Option, -) -> Result { - let start_len = buf.len(); - let start_cap = buf.capacity(); - // Optionally limit the maximum bytes read on each iteration. - // This adds an arbitrary fiddle factor to allow for more data than we expect. - let mut max_read_size = size_hint - .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE)) - .unwrap_or(DEFAULT_BUF_SIZE); - - let mut initialized = 0; // Extra initialized bytes from previous loop iteration - - const PROBE_SIZE: usize = 32; - - fn small_probe_read(r: &mut R, buf: &mut Vec) -> Result { - let mut probe = [0u8; PROBE_SIZE]; - - loop { - match r.read(&mut probe) { - Ok(n) => { - // there is no way to recover from allocation failure here - // because the data has already been read. - buf.extend_from_slice(&probe[..n]); - return Ok(n); - } - Err(ref e) if e.is_interrupted() => continue, - Err(e) => return Err(e), - } - } - } - - // avoid inflating empty/small vecs before we have determined that there's anything to read - if (size_hint.is_none() || size_hint == Some(0)) && buf.capacity() - buf.len() < PROBE_SIZE { - let read = small_probe_read(r, buf)?; - - if read == 0 { - return Ok(0); - } - } - - let mut consecutive_short_reads = 0; - - loop { - if buf.len() == buf.capacity() && buf.capacity() == start_cap { - // The buffer might be an exact fit. Let's read into a probe buffer - // and see if it returns `Ok(0)`. If so, we've avoided an - // unnecessary doubling of the capacity. But if not, append the - // probe buffer to the primary buffer and let its capacity grow. - let read = small_probe_read(r, buf)?; - - if read == 0 { - return Ok(buf.len() - start_len); - } - } - - if buf.len() == buf.capacity() { - // buf is full, need more space - buf.try_reserve(PROBE_SIZE)?; - } - - let mut spare = buf.spare_capacity_mut(); - let buf_len = cmp::min(spare.len(), max_read_size); - spare = &mut spare[..buf_len]; - let mut read_buf: BorrowedBuf<'_> = spare.into(); - - // SAFETY: These bytes were initialized but not filled in the previous loop - unsafe { - read_buf.set_init(initialized); - } - - let mut cursor = read_buf.unfilled(); - let result = loop { - match r.read_buf(cursor.reborrow()) { - Err(e) if e.is_interrupted() => continue, - // Do not stop now in case of error: we might have received both data - // and an error - res => break res, - } - }; - - let unfilled_but_initialized = cursor.init_mut().len(); - let bytes_read = cursor.written(); - let was_fully_initialized = read_buf.init_len() == buf_len; - - // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. - unsafe { - let new_len = bytes_read + buf.len(); - buf.set_len(new_len); - } - - // Now that all data is pushed to the vector, we can fail without data loss - result?; - - if bytes_read == 0 { - return Ok(buf.len() - start_len); - } - - if bytes_read < buf_len { - consecutive_short_reads += 1; - } else { - consecutive_short_reads = 0; - } - - // store how much was initialized but not filled - initialized = unfilled_but_initialized; - - // Use heuristics to determine the max read size if no initial size hint was provided - if size_hint.is_none() { - // The reader is returning short reads but it doesn't call ensure_init(). - // In that case we no longer need to restrict read sizes to avoid - // initialization costs. - // When reading from disk we usually don't get any short reads except at EOF. - // So we wait for at least 2 short reads before uncapping the read buffer; - // this helps with the Windows issue. - if !was_fully_initialized && consecutive_short_reads > 1 { - max_read_size = usize::MAX; - } - - // we have passed a larger buffer than previously and the - // reader still hasn't returned a short read - if buf_len >= max_read_size && bytes_read == buf_len { - max_read_size = max_read_size.saturating_mul(2); - } - } - } -} - -pub(crate) fn default_read_to_string( - r: &mut R, - buf: &mut String, - size_hint: Option, -) -> Result { - // Note that we do *not* call `r.read_to_end()` here. We are passing - // `&mut Vec` (the raw contents of `buf`) into the `read_to_end` - // method to fill it up. An arbitrary implementation could overwrite the - // entire contents of the vector, not just append to it (which is what - // we are expecting). - // - // To prevent extraneously checking the UTF-8-ness of the entire buffer - // we pass it to our hardcoded `default_read_to_end` implementation which - // we know is guaranteed to only read data into the end of the buffer. - unsafe { append_to_string(buf, |b| default_read_to_end(r, b, size_hint)) } -} - -pub(crate) fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result -where - F: FnOnce(&mut [u8]) -> Result, -{ - let buf = bufs.iter_mut().find(|b| !b.is_empty()).map_or(&mut [][..], |b| &mut **b); - read(buf) -} - -pub(crate) fn default_write_vectored(write: F, bufs: &[IoSlice<'_>]) -> Result -where - F: FnOnce(&[u8]) -> Result, -{ - let buf = bufs.iter().find(|b| !b.is_empty()).map_or(&[][..], |b| &**b); - write(buf) -} - -pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [u8]) -> Result<()> { - while !buf.is_empty() { - match this.read(buf) { - Ok(0) => break, - Ok(n) => { - buf = &mut buf[n..]; - } - Err(ref e) if e.is_interrupted() => {} - Err(e) => return Err(e), - } - } - if !buf.is_empty() { Err(Error::READ_EXACT_EOF) } else { Ok(()) } -} - -pub(crate) fn default_read_buf(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()> -where - F: FnOnce(&mut [u8]) -> Result, -{ - let n = read(cursor.ensure_init().init_mut())?; - cursor.advance(n); - Ok(()) -} - -pub(crate) fn default_read_buf_exact( - this: &mut R, - mut cursor: BorrowedCursor<'_>, -) -> Result<()> { - while cursor.capacity() > 0 { - let prev_written = cursor.written(); - match this.read_buf(cursor.reborrow()) { - Ok(()) => {} - Err(e) if e.is_interrupted() => continue, - Err(e) => return Err(e), - } - - if cursor.written() == prev_written { - return Err(Error::READ_EXACT_EOF); - } - } - - Ok(()) -} - -pub(crate) fn default_write_fmt( - this: &mut W, - args: fmt::Arguments<'_>, -) -> Result<()> { - // Create a shim which translates a `Write` to a `fmt::Write` and saves off - // I/O errors, instead of discarding them. - struct Adapter<'a, T: ?Sized + 'a> { - inner: &'a mut T, - error: Result<()>, - } - - impl fmt::Write for Adapter<'_, T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } - } - - let mut output = Adapter { inner: this, error: Ok(()) }; - match fmt::write(&mut output, args) { - Ok(()) => Ok(()), - Err(..) => { - // Check whether the error came from the underlying `Write`. - if output.error.is_err() { - output.error - } else { - // This shouldn't happen: the underlying stream did not error, - // but somehow the formatter still errored? - panic!( - "a formatting trait implementation returned an error when the underlying stream did not" - ); - } - } - } -} - -/// The `Read` trait allows for reading bytes from a source. -/// -/// Implementors of the `Read` trait are called 'readers'. -/// -/// Readers are defined by one required method, [`read()`]. Each call to [`read()`] -/// will attempt to pull bytes from this source into a provided buffer. A -/// number of other methods are implemented in terms of [`read()`], giving -/// implementors a number of ways to read bytes while only needing to implement -/// a single method. -/// -/// Readers are intended to be composable with one another. Many implementors -/// throughout [`std::io`] take and provide types which implement the `Read` -/// trait. -/// -/// Please note that each call to [`read()`] may involve a system call, and -/// therefore, using something that implements [`BufRead`], such as -/// [`BufReader`], will be more efficient. -/// -/// Repeated calls to the reader use the same cursor, so for example -/// calling `read_to_end` twice on a [`File`] will only return the file's -/// contents once. It's recommended to first call `rewind()` in that case. -/// -/// # Examples -/// -/// [`File`]s implement `Read`: -/// -/// ```no_run -/// use std::io; -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// fn main() -> io::Result<()> { -/// let mut f = File::open("foo.txt")?; -/// let mut buffer = [0; 10]; -/// -/// // read up to 10 bytes -/// f.read(&mut buffer)?; -/// -/// let mut buffer = Vec::new(); -/// // read the whole file -/// f.read_to_end(&mut buffer)?; -/// -/// // read into a String, so that you don't need to do the conversion. -/// let mut buffer = String::new(); -/// f.read_to_string(&mut buffer)?; -/// -/// // and more! See the other methods for more details. -/// Ok(()) -/// } -/// ``` -/// -/// Read from [`&str`] because [`&[u8]`][prim@slice] implements `Read`: -/// -/// ```no_run -/// # use std::io; -/// use std::io::prelude::*; -/// -/// fn main() -> io::Result<()> { -/// let mut b = "This string will be read".as_bytes(); -/// let mut buffer = [0; 10]; -/// -/// // read up to 10 bytes -/// b.read(&mut buffer)?; -/// -/// // etc... it works exactly as a File does! -/// Ok(()) -/// } -/// ``` -/// -/// [`read()`]: Read::read -/// [`&str`]: prim@str -/// [`std::io`]: self -/// [`File`]: crate::fs::File -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(notable_trait)] -#[cfg_attr(not(test), rustc_diagnostic_item = "IoRead")] -pub trait Read { - /// Pull some bytes from this source into the specified buffer, returning - /// how many bytes were read. - /// - /// This function does not provide any guarantees about whether it blocks - /// waiting for data, but if an object needs to block for a read and cannot, - /// it will typically signal this via an [`Err`] return value. - /// - /// If the return value of this method is [`Ok(n)`], then implementations must - /// guarantee that `0 <= n <= buf.len()`. A nonzero `n` value indicates - /// that the buffer `buf` has been filled in with `n` bytes of data from this - /// source. If `n` is `0`, then it can indicate one of two scenarios: - /// - /// 1. This reader has reached its "end of file" and will likely no longer - /// be able to produce bytes. Note that this does not mean that the - /// reader will *always* no longer be able to produce bytes. As an example, - /// on Linux, this method will call the `recv` syscall for a [`TcpStream`], - /// where returning zero indicates the connection was shut down correctly. While - /// for [`File`], it is possible to reach the end of file and get zero as result, - /// but if more data is appended to the file, future calls to `read` will return - /// more data. - /// 2. The buffer specified was 0 bytes in length. - /// - /// It is not an error if the returned value `n` is smaller than the buffer size, - /// even when the reader is not at the end of the stream yet. - /// This may happen for example because fewer bytes are actually available right now - /// (e. g. being close to end-of-file) or because read() was interrupted by a signal. - /// - /// As this trait is safe to implement, callers in unsafe code cannot rely on - /// `n <= buf.len()` for safety. - /// Extra care needs to be taken when `unsafe` functions are used to access the read bytes. - /// Callers have to ensure that no unchecked out-of-bounds accesses are possible even if - /// `n > buf.len()`. - /// - /// *Implementations* of this method can make no assumptions about the contents of `buf` when - /// this function is called. It is recommended that implementations only write data to `buf` - /// instead of reading its contents. - /// - /// Correspondingly, however, *callers* of this method in unsafe code must not assume - /// any guarantees about how the implementation uses `buf`. The trait is safe to implement, - /// so it is possible that the code that's supposed to write to the buffer might also read - /// from it. It is your responsibility to make sure that `buf` is initialized - /// before calling `read`. Calling `read` with an uninitialized `buf` (of the kind one - /// obtains via [`MaybeUninit`]) is not safe, and can lead to undefined behavior. - /// - /// [`MaybeUninit`]: crate::mem::MaybeUninit - /// - /// # Errors - /// - /// If this function encounters any form of I/O or other error, an error - /// variant will be returned. If an error is returned then it must be - /// guaranteed that no bytes were read. - /// - /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read - /// operation should be retried if there is nothing else to do. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`Ok(n)`]: Ok - /// [`File`]: crate::fs::File - /// [`TcpStream`]: crate::net::TcpStream - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; - /// - /// // read up to 10 bytes - /// let n = f.read(&mut buffer[..])?; - /// - /// println!("The bytes: {:?}", &buffer[..n]); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn read(&mut self, buf: &mut [u8]) -> Result; - - /// Like `read`, except that it reads into a slice of buffers. - /// - /// Data is copied to fill each buffer in order, with the final buffer - /// written to possibly being only partially filled. This method must - /// behave equivalently to a single call to `read` with concatenated - /// buffers. - /// - /// The default implementation calls `read` with either the first nonempty - /// buffer provided, or an empty one if none exists. - #[stable(feature = "iovec", since = "1.36.0")] - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - default_read_vectored(|b| self.read(b), bufs) - } - - /// Determines if this `Read`er has an efficient `read_vectored` - /// implementation. - /// - /// If a `Read`er does not override the default `read_vectored` - /// implementation, code using it may want to avoid the method all together - /// and coalesce writes into a single buffer for higher performance. - /// - /// The default implementation returns `false`. - #[unstable(feature = "can_vector", issue = "69941")] - fn is_read_vectored(&self) -> bool { - false - } - - /// Reads all bytes until EOF in this source, placing them into `buf`. - /// - /// All bytes read from this source will be appended to the specified buffer - /// `buf`. This function will continuously call [`read()`] to append more data to - /// `buf` until [`read()`] returns either [`Ok(0)`] or an error of - /// non-[`ErrorKind::Interrupted`] kind. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation - /// will continue. - /// - /// If any other read error is encountered then this function immediately - /// returns. Any bytes which have already been read will be appended to - /// `buf`. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`read()`]: Read::read - /// [`Ok(0)`]: Ok - /// [`File`]: crate::fs::File - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = Vec::new(); - /// - /// // read the whole file - /// f.read_to_end(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - /// - /// (See also the [`std::fs::read`] convenience function for reading from a - /// file.) - /// - /// [`std::fs::read`]: crate::fs::read - /// - /// ## Implementing `read_to_end` - /// - /// When implementing the `io::Read` trait, it is recommended to allocate - /// memory using [`Vec::try_reserve`]. However, this behavior is not guaranteed - /// by all implementations, and `read_to_end` may not handle out-of-memory - /// situations gracefully. - /// - /// ```no_run - /// # use std::io::{self, BufRead}; - /// # struct Example { example_datasource: io::Empty } impl Example { - /// # fn get_some_data_for_the_example(&self) -> &'static [u8] { &[] } - /// fn read_to_end(&mut self, dest_vec: &mut Vec) -> io::Result { - /// let initial_vec_len = dest_vec.len(); - /// loop { - /// let src_buf = self.example_datasource.fill_buf()?; - /// if src_buf.is_empty() { - /// break; - /// } - /// dest_vec.try_reserve(src_buf.len())?; - /// dest_vec.extend_from_slice(src_buf); - /// - /// // Any irreversible side effects should happen after `try_reserve` succeeds, - /// // to avoid losing data on allocation error. - /// let read = src_buf.len(); - /// self.example_datasource.consume(read); - /// } - /// Ok(dest_vec.len() - initial_vec_len) - /// } - /// # } - /// ``` - /// - /// # Usage Notes - /// - /// `read_to_end` attempts to read a source until EOF, but many sources are continuous streams - /// that do not send EOF. In these cases, `read_to_end` will block indefinitely. Standard input - /// is one such stream which may be finite if piped, but is typically continuous. For example, - /// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. - /// Reading user input or running programs that remain open indefinitely will never terminate - /// the stream with `EOF` (e.g. `yes | my-rust-program`). - /// - /// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution - /// - ///[`read`]: Read::read - /// - /// [`Vec::try_reserve`]: crate::vec::Vec::try_reserve - #[stable(feature = "rust1", since = "1.0.0")] - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - default_read_to_end(self, buf, None) - } - - /// Reads all bytes until EOF in this source, appending them to `buf`. - /// - /// If successful, this function returns the number of bytes which were read - /// and appended to `buf`. - /// - /// # Errors - /// - /// If the data in this stream is *not* valid UTF-8 then an error is - /// returned and `buf` is unchanged. - /// - /// See [`read_to_end`] for other error semantics. - /// - /// [`read_to_end`]: Read::read_to_end - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: crate::fs::File - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = String::new(); - /// - /// f.read_to_string(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - /// - /// (See also the [`std::fs::read_to_string`] convenience function for - /// reading from a file.) - /// - /// # Usage Notes - /// - /// `read_to_string` attempts to read a source until EOF, but many sources are continuous streams - /// that do not send EOF. In these cases, `read_to_string` will block indefinitely. Standard input - /// is one such stream which may be finite if piped, but is typically continuous. For example, - /// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. - /// Reading user input or running programs that remain open indefinitely will never terminate - /// the stream with `EOF` (e.g. `yes | my-rust-program`). - /// - /// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution - /// - ///[`read`]: Read::read - /// - /// [`std::fs::read_to_string`]: crate::fs::read_to_string - #[stable(feature = "rust1", since = "1.0.0")] - fn read_to_string(&mut self, buf: &mut String) -> Result { - default_read_to_string(self, buf, None) - } - - /// Reads the exact number of bytes required to fill `buf`. - /// - /// This function reads as many bytes as necessary to completely fill the - /// specified buffer `buf`. - /// - /// *Implementations* of this method can make no assumptions about the contents of `buf` when - /// this function is called. It is recommended that implementations only write data to `buf` - /// instead of reading its contents. The documentation on [`read`] has a more detailed - /// explanation of this subject. - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation - /// will continue. - /// - /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. - /// The contents of `buf` are unspecified in this case. - /// - /// If any other read error is encountered then this function immediately - /// returns. The contents of `buf` are unspecified in this case. - /// - /// If this function returns an error, it is unspecified how many bytes it - /// has read, but it will never read more than would be necessary to - /// completely fill the buffer. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`read`]: Read::read - /// [`File`]: crate::fs::File - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; - /// - /// // read exactly 10 bytes - /// f.read_exact(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "read_exact", since = "1.6.0")] - fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { - default_read_exact(self, buf) - } - - /// Pull some bytes from this source into the specified buffer. - /// - /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use - /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`. - /// - /// The default implementation delegates to `read`. - /// - /// This method makes it possible to return both data and an error but it is advised against. - #[unstable(feature = "read_buf", issue = "78485")] - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { - default_read_buf(|b| self.read(b), buf) - } - - /// Reads the exact number of bytes required to fill `cursor`. - /// - /// This is similar to the [`read_exact`](Read::read_exact) method, except - /// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use - /// with uninitialized buffers. - /// - /// # Errors - /// - /// If this function encounters an error of the kind [`ErrorKind::Interrupted`] - /// then the error is ignored and the operation will continue. - /// - /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. - /// - /// If any other read error is encountered then this function immediately - /// returns. - /// - /// If this function returns an error, all bytes read will be appended to `cursor`. - #[unstable(feature = "read_buf", issue = "78485")] - fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> { - default_read_buf_exact(self, cursor) - } - - /// Creates a "by reference" adapter for this instance of `Read`. - /// - /// The returned adapter also implements `Read` and will simply borrow this - /// current reader. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: crate::fs::File - /// - /// ```no_run - /// use std::io; - /// use std::io::Read; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = Vec::new(); - /// let mut other_buffer = Vec::new(); - /// - /// { - /// let reference = f.by_ref(); - /// - /// // read at most 5 bytes - /// reference.take(5).read_to_end(&mut buffer)?; - /// - /// } // drop our &mut reference so we can use f again - /// - /// // original file still usable, read the rest - /// f.read_to_end(&mut other_buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn by_ref(&mut self) -> &mut Self - where - Self: Sized, - { - self - } - - /// Transforms this `Read` instance to an [`Iterator`] over its bytes. - /// - /// The returned type implements [`Iterator`] where the [`Item`] is - /// [Result]<[u8], [io::Error]>. - /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`] - /// otherwise. EOF is mapped to returning [`None`] from this iterator. - /// - /// The default implementation calls `read` for each byte, - /// which can be very inefficient for data that's not in memory, - /// such as [`File`]. Consider using a [`BufReader`] in such cases. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`Item`]: Iterator::Item - /// [`File`]: crate::fs::File "fs::File" - /// [Result]: crate::result::Result "Result" - /// [io::Error]: self::Error "io::Error" - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let f = BufReader::new(File::open("foo.txt")?); - /// - /// for byte in f.bytes() { - /// println!("{}", byte?); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn bytes(self) -> Bytes - where - Self: Sized, - { - Bytes { inner: self } - } - - /// Creates an adapter which will chain this stream with another. - /// - /// The returned `Read` instance will first read all bytes from this object - /// until EOF is encountered. Afterwards the output is equivalent to the - /// output of `next`. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: crate::fs::File - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let f1 = File::open("foo.txt")?; - /// let f2 = File::open("bar.txt")?; - /// - /// let mut handle = f1.chain(f2); - /// let mut buffer = String::new(); - /// - /// // read the value into a String. We could use any Read method here, - /// // this is just one example. - /// handle.read_to_string(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn chain(self, next: R) -> Chain - where - Self: Sized, - { - Chain { first: self, second: next, done_first: false } - } - - /// Creates an adapter which will read at most `limit` bytes from it. - /// - /// This function returns a new instance of `Read` which will read at most - /// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any - /// read errors will not count towards the number of bytes read and future - /// calls to [`read()`] may succeed. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: crate::fs::File - /// [`Ok(0)`]: Ok - /// [`read()`]: Read::read - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let f = File::open("foo.txt")?; - /// let mut buffer = [0; 5]; - /// - /// // read at most five bytes - /// let mut handle = f.take(5); - /// - /// handle.read(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn take(self, limit: u64) -> Take - where - Self: Sized, - { - Take { inner: self, len: limit, limit } - } - - /// Read and return a fixed array of bytes from this source. - /// - /// This function uses an array sized based on a const generic size known at compile time. You - /// can specify the size with turbofish (`reader.read_array::<8>()`), or let type inference - /// determine the number of bytes needed based on how the return value gets used. For instance, - /// this function works well with functions like [`u64::from_le_bytes`] to turn an array of - /// bytes into an integer of the same size. - /// - /// Like `read_exact`, if this function encounters an "end of file" before reading the desired - /// number of bytes, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. - /// - /// ``` - /// #![feature(read_array)] - /// use std::io::Cursor; - /// use std::io::prelude::*; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2]); - /// let x = u64::from_le_bytes(buf.read_array()?); - /// let y = u32::from_be_bytes(buf.read_array()?); - /// let z = u16::from_be_bytes(buf.read_array()?); - /// assert_eq!(x, 0x807060504030201); - /// assert_eq!(y, 0x9080706); - /// assert_eq!(z, 0x504); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "read_array", issue = "148848")] - fn read_array(&mut self) -> Result<[u8; N]> - where - Self: Sized, - { - let mut buf = [MaybeUninit::uninit(); N]; - let mut borrowed_buf = BorrowedBuf::from(buf.as_mut_slice()); - self.read_buf_exact(borrowed_buf.unfilled())?; - // Guard against incorrect `read_buf_exact` implementations. - assert_eq!(borrowed_buf.len(), N); - Ok(unsafe { MaybeUninit::array_assume_init(buf) }) - } -} - -/// Reads all bytes from a [reader][Read] into a new [`String`]. -/// -/// This is a convenience function for [`Read::read_to_string`]. Using this -/// function avoids having to create a variable first and provides more type -/// safety since you can only get the buffer out if there were no errors. (If you -/// use [`Read::read_to_string`] you have to remember to check whether the read -/// succeeded because otherwise your buffer will be empty or only partially full.) -/// -/// # Performance -/// -/// The downside of this function's increased ease of use and type safety is -/// that it gives you less control over performance. For example, you can't -/// pre-allocate memory like you can using [`String::with_capacity`] and -/// [`Read::read_to_string`]. Also, you can't re-use the buffer if an error -/// occurs while reading. -/// -/// In many cases, this function's performance will be adequate and the ease of use -/// and type safety tradeoffs will be worth it. However, there are cases where you -/// need more control over performance, and in those cases you should definitely use -/// [`Read::read_to_string`] directly. -/// -/// Note that in some special cases, such as when reading files, this function will -/// pre-allocate memory based on the size of the input it is reading. In those -/// cases, the performance should be as good as if you had used -/// [`Read::read_to_string`] with a manually pre-allocated buffer. -/// -/// # Errors -/// -/// This function forces you to handle errors because the output (the `String`) -/// is wrapped in a [`Result`]. See [`Read::read_to_string`] for the errors -/// that can occur. If any error occurs, you will get an [`Err`], so you -/// don't have to worry about your buffer being empty or partially full. -/// -/// # Examples -/// -/// ```no_run -/// # use std::io; -/// fn main() -> io::Result<()> { -/// let stdin = io::read_to_string(io::stdin())?; -/// println!("Stdin was:"); -/// println!("{stdin}"); -/// Ok(()) -/// } -/// ``` -/// -/// # Usage Notes -/// -/// `read_to_string` attempts to read a source until EOF, but many sources are continuous streams -/// that do not send EOF. In these cases, `read_to_string` will block indefinitely. Standard input -/// is one such stream which may be finite if piped, but is typically continuous. For example, -/// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. -/// Reading user input or running programs that remain open indefinitely will never terminate -/// the stream with `EOF` (e.g. `yes | my-rust-program`). -/// -/// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution -/// -///[`read`]: Read::read -/// -#[stable(feature = "io_read_to_string", since = "1.65.0")] -pub fn read_to_string(mut reader: R) -> Result { - let mut buf = String::new(); - reader.read_to_string(&mut buf)?; - Ok(buf) -} - -/// A buffer type used with `Read::read_vectored`. -/// -/// It is semantically a wrapper around a `&mut [u8]`, but is guaranteed to be -/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on -/// Windows. -#[stable(feature = "iovec", since = "1.36.0")] -#[repr(transparent)] -pub struct IoSliceMut<'a>(sys::io::IoSliceMut<'a>); - -#[stable(feature = "iovec_send_sync", since = "1.44.0")] -unsafe impl<'a> Send for IoSliceMut<'a> {} - -#[stable(feature = "iovec_send_sync", since = "1.44.0")] -unsafe impl<'a> Sync for IoSliceMut<'a> {} - -#[stable(feature = "iovec", since = "1.36.0")] -impl<'a> fmt::Debug for IoSliceMut<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.0.as_slice(), fmt) - } -} - -impl<'a> IoSliceMut<'a> { - /// Creates a new `IoSliceMut` wrapping a byte slice. - /// - /// # Panics - /// - /// Panics on Windows if the slice is larger than 4GB. - #[stable(feature = "iovec", since = "1.36.0")] - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut(sys::io::IoSliceMut::new(buf)) - } - - /// Advance the internal cursor of the slice. - /// - /// Also see [`IoSliceMut::advance_slices`] to advance the cursors of - /// multiple buffers. - /// - /// # Panics - /// - /// Panics when trying to advance beyond the end of the slice. - /// - /// # Examples - /// - /// ``` - /// use std::io::IoSliceMut; - /// use std::ops::Deref; - /// - /// let mut data = [1; 8]; - /// let mut buf = IoSliceMut::new(&mut data); - /// - /// // Mark 3 bytes as read. - /// buf.advance(3); - /// assert_eq!(buf.deref(), [1; 5].as_ref()); - /// ``` - #[stable(feature = "io_slice_advance", since = "1.81.0")] - #[inline] - pub fn advance(&mut self, n: usize) { - self.0.advance(n) - } - - /// Advance a slice of slices. - /// - /// Shrinks the slice to remove any `IoSliceMut`s that are fully advanced over. - /// If the cursor ends up in the middle of an `IoSliceMut`, it is modified - /// to start at that cursor. - /// - /// For example, if we have a slice of two 8-byte `IoSliceMut`s, and we advance by 10 bytes, - /// the result will only include the second `IoSliceMut`, advanced by 2 bytes. - /// - /// # Panics - /// - /// Panics when trying to advance beyond the end of the slices. - /// - /// # Examples - /// - /// ``` - /// use std::io::IoSliceMut; - /// use std::ops::Deref; - /// - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), - /// ][..]; - /// - /// // Mark 10 bytes as read. - /// IoSliceMut::advance_slices(&mut bufs, 10); - /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); - /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - /// ``` - #[stable(feature = "io_slice_advance", since = "1.81.0")] - #[inline] - pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) { - // Number of buffers to remove. - let mut remove = 0; - // Remaining length before reaching n. - let mut left = n; - for buf in bufs.iter() { - if let Some(remainder) = left.checked_sub(buf.len()) { - left = remainder; - remove += 1; - } else { - break; - } - } - - *bufs = &mut take(bufs)[remove..]; - if bufs.is_empty() { - assert!(left == 0, "advancing io slices beyond their length"); - } else { - bufs[0].advance(left); - } - } - - /// Get the underlying bytes as a mutable slice with the original lifetime. - /// - /// # Examples - /// - /// ``` - /// #![feature(io_slice_as_bytes)] - /// use std::io::IoSliceMut; - /// - /// let mut data = *b"abcdef"; - /// let io_slice = IoSliceMut::new(&mut data); - /// io_slice.into_slice()[0] = b'A'; - /// - /// assert_eq!(&data, b"Abcdef"); - /// ``` - #[unstable(feature = "io_slice_as_bytes", issue = "132818")] - pub const fn into_slice(self) -> &'a mut [u8] { - self.0.into_slice() - } -} - -#[stable(feature = "iovec", since = "1.36.0")] -impl<'a> Deref for IoSliceMut<'a> { - type Target = [u8]; - - #[inline] - fn deref(&self) -> &[u8] { - self.0.as_slice() - } -} - -#[stable(feature = "iovec", since = "1.36.0")] -impl<'a> DerefMut for IoSliceMut<'a> { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - self.0.as_mut_slice() - } -} - -/// A buffer type used with `Write::write_vectored`. -/// -/// It is semantically a wrapper around a `&[u8]`, but is guaranteed to be -/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on -/// Windows. -#[stable(feature = "iovec", since = "1.36.0")] -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a>(sys::io::IoSlice<'a>); - -#[stable(feature = "iovec_send_sync", since = "1.44.0")] -unsafe impl<'a> Send for IoSlice<'a> {} - -#[stable(feature = "iovec_send_sync", since = "1.44.0")] -unsafe impl<'a> Sync for IoSlice<'a> {} - -#[stable(feature = "iovec", since = "1.36.0")] -impl<'a> fmt::Debug for IoSlice<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.0.as_slice(), fmt) - } -} - -impl<'a> IoSlice<'a> { - /// Creates a new `IoSlice` wrapping a byte slice. - /// - /// # Panics - /// - /// Panics on Windows if the slice is larger than 4GB. - #[stable(feature = "iovec", since = "1.36.0")] - #[must_use] - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice(sys::io::IoSlice::new(buf)) - } - - /// Advance the internal cursor of the slice. - /// - /// Also see [`IoSlice::advance_slices`] to advance the cursors of multiple - /// buffers. - /// - /// # Panics - /// - /// Panics when trying to advance beyond the end of the slice. - /// - /// # Examples - /// - /// ``` - /// use std::io::IoSlice; - /// use std::ops::Deref; - /// - /// let data = [1; 8]; - /// let mut buf = IoSlice::new(&data); - /// - /// // Mark 3 bytes as read. - /// buf.advance(3); - /// assert_eq!(buf.deref(), [1; 5].as_ref()); - /// ``` - #[stable(feature = "io_slice_advance", since = "1.81.0")] - #[inline] - pub fn advance(&mut self, n: usize) { - self.0.advance(n) - } - - /// Advance a slice of slices. - /// - /// Shrinks the slice to remove any `IoSlice`s that are fully advanced over. - /// If the cursor ends up in the middle of an `IoSlice`, it is modified - /// to start at that cursor. - /// - /// For example, if we have a slice of two 8-byte `IoSlice`s, and we advance by 10 bytes, - /// the result will only include the second `IoSlice`, advanced by 2 bytes. - /// - /// # Panics - /// - /// Panics when trying to advance beyond the end of the slices. - /// - /// # Examples - /// - /// ``` - /// use std::io::IoSlice; - /// use std::ops::Deref; - /// - /// let buf1 = [1; 8]; - /// let buf2 = [2; 16]; - /// let buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSlice::new(&buf1), - /// IoSlice::new(&buf2), - /// IoSlice::new(&buf3), - /// ][..]; - /// - /// // Mark 10 bytes as written. - /// IoSlice::advance_slices(&mut bufs, 10); - /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); - /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - #[stable(feature = "io_slice_advance", since = "1.81.0")] - #[inline] - pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) { - // Number of buffers to remove. - let mut remove = 0; - // Remaining length before reaching n. This prevents overflow - // that could happen if the length of slices in `bufs` were instead - // accumulated. Those slice may be aliased and, if they are large - // enough, their added length may overflow a `usize`. - let mut left = n; - for buf in bufs.iter() { - if let Some(remainder) = left.checked_sub(buf.len()) { - left = remainder; - remove += 1; - } else { - break; - } - } - - *bufs = &mut take(bufs)[remove..]; - if bufs.is_empty() { - assert!(left == 0, "advancing io slices beyond their length"); - } else { - bufs[0].advance(left); - } - } - - /// Get the underlying bytes as a slice with the original lifetime. - /// - /// This doesn't borrow from `self`, so is less restrictive than calling - /// `.deref()`, which does. - /// - /// # Examples - /// - /// ``` - /// #![feature(io_slice_as_bytes)] - /// use std::io::IoSlice; - /// - /// let data = b"abcdef"; - /// - /// let mut io_slice = IoSlice::new(data); - /// let tail = &io_slice.as_slice()[3..]; - /// - /// // This works because `tail` doesn't borrow `io_slice` - /// io_slice = IoSlice::new(tail); - /// - /// assert_eq!(io_slice.as_slice(), b"def"); - /// ``` - #[unstable(feature = "io_slice_as_bytes", issue = "132818")] - pub const fn as_slice(self) -> &'a [u8] { - self.0.as_slice() - } -} - -#[stable(feature = "iovec", since = "1.36.0")] -impl<'a> Deref for IoSlice<'a> { - type Target = [u8]; - - #[inline] - fn deref(&self) -> &[u8] { - self.0.as_slice() - } -} - -/// A trait for objects which are byte-oriented sinks. -/// -/// Implementors of the `Write` trait are sometimes called 'writers'. -/// -/// Writers are defined by two required methods, [`write`] and [`flush`]: -/// -/// * The [`write`] method will attempt to write some data into the object, -/// returning how many bytes were successfully written. -/// -/// * The [`flush`] method is useful for adapters and explicit buffers -/// themselves for ensuring that all buffered data has been pushed out to the -/// 'true sink'. -/// -/// Writers are intended to be composable with one another. Many implementors -/// throughout [`std::io`] take and provide types which implement the `Write` -/// trait. -/// -/// [`write`]: Write::write -/// [`flush`]: Write::flush -/// [`std::io`]: self -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let data = b"some bytes"; -/// -/// let mut pos = 0; -/// let mut buffer = File::create("foo.txt")?; -/// -/// while pos < data.len() { -/// let bytes_written = buffer.write(&data[pos..])?; -/// pos += bytes_written; -/// } -/// Ok(()) -/// } -/// ``` -/// -/// The trait also provides convenience methods like [`write_all`], which calls -/// `write` in a loop until its entire input has been written. -/// -/// [`write_all`]: Write::write_all -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(notable_trait)] -#[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")] -pub trait Write { - /// Writes a buffer into this writer, returning how many bytes were written. - /// - /// This function will attempt to write the entire contents of `buf`, but - /// the entire write might not succeed, or the write may also generate an - /// error. Typically, a call to `write` represents one attempt to write to - /// any wrapped object. - /// - /// Calls to `write` are not guaranteed to block waiting for data to be - /// written, and a write which would otherwise block can be indicated through - /// an [`Err`] variant. - /// - /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. - /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`. - /// A return value of `Ok(0)` typically means that the underlying object is - /// no longer able to accept bytes and will likely not be able to in the - /// future as well, or that the buffer provided is empty. - /// - /// # Errors - /// - /// Each call to `write` may generate an I/O error indicating that the - /// operation could not be completed. If an error is returned then no bytes - /// in the buffer were written to this writer. - /// - /// It is **not** considered an error if the entire buffer could not be - /// written to this writer. - /// - /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the - /// write operation should be retried if there is nothing else to do. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // Writes some prefix of the byte string, not necessarily all of it. - /// buffer.write(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - /// - /// [`Ok(n)`]: Ok - #[stable(feature = "rust1", since = "1.0.0")] - fn write(&mut self, buf: &[u8]) -> Result; - - /// Like [`write`], except that it writes from a slice of buffers. - /// - /// Data is copied from each buffer in order, with the final buffer - /// read from possibly being only partially consumed. This method must - /// behave as a call to [`write`] with the buffers concatenated would. - /// - /// The default implementation calls [`write`] with either the first nonempty - /// buffer provided, or an empty one if none exists. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::IoSlice; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let data1 = [1; 8]; - /// let data2 = [15; 8]; - /// let io_slice1 = IoSlice::new(&data1); - /// let io_slice2 = IoSlice::new(&data2); - /// - /// let mut buffer = File::create("foo.txt")?; - /// - /// // Writes some prefix of the byte string, not necessarily all of it. - /// buffer.write_vectored(&[io_slice1, io_slice2])?; - /// Ok(()) - /// } - /// ``` - /// - /// [`write`]: Write::write - #[stable(feature = "iovec", since = "1.36.0")] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - default_write_vectored(|b| self.write(b), bufs) - } - - /// Determines if this `Write`r has an efficient [`write_vectored`] - /// implementation. - /// - /// If a `Write`r does not override the default [`write_vectored`] - /// implementation, code using it may want to avoid the method all together - /// and coalesce writes into a single buffer for higher performance. - /// - /// The default implementation returns `false`. - /// - /// [`write_vectored`]: Write::write_vectored - #[unstable(feature = "can_vector", issue = "69941")] - fn is_write_vectored(&self) -> bool { - false - } - - /// Flushes this output stream, ensuring that all intermediately buffered - /// contents reach their destination. - /// - /// # Errors - /// - /// It is considered an error if not all bytes could be written due to - /// I/O errors or EOF being reached. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::io::BufWriter; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = BufWriter::new(File::create("foo.txt")?); - /// - /// buffer.write_all(b"some bytes")?; - /// buffer.flush()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn flush(&mut self) -> Result<()>; - - /// Attempts to write an entire buffer into this writer. - /// - /// This method will continuously call [`write`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is - /// returned. This method will not return until the entire buffer has been - /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be - /// returned. - /// - /// If the buffer contains no data, this will never call [`write`]. - /// - /// # Errors - /// - /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns. - /// - /// [`write`]: Write::write - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// buffer.write_all(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { - while !buf.is_empty() { - match self.write(buf) { - Ok(0) => { - return Err(Error::WRITE_ALL_EOF); - } - Ok(n) => buf = &buf[n..], - Err(ref e) if e.is_interrupted() => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Attempts to write multiple buffers into this writer. - /// - /// This method will continuously call [`write_vectored`] until there is no - /// more data to be written or an error of non-[`ErrorKind::Interrupted`] - /// kind is returned. This method will not return until all buffers have - /// been successfully written or such an error occurs. The first error that - /// is not of [`ErrorKind::Interrupted`] kind generated from this method - /// will be returned. - /// - /// If the buffer contains no data, this will never call [`write_vectored`]. - /// - /// # Notes - /// - /// Unlike [`write_vectored`], this takes a *mutable* reference to - /// a slice of [`IoSlice`]s, not an immutable one. That's because we need to - /// modify the slice to keep track of the bytes already written. - /// - /// Once this function returns, the contents of `bufs` are unspecified, as - /// this depends on how many calls to [`write_vectored`] were necessary. It is - /// best to understand this function as taking ownership of `bufs` and to - /// not use `bufs` afterwards. The underlying buffers, to which the - /// [`IoSlice`]s point (but not the [`IoSlice`]s themselves), are unchanged and - /// can be reused. - /// - /// [`write_vectored`]: Write::write_vectored - /// - /// # Examples - /// - /// ``` - /// #![feature(write_all_vectored)] - /// # fn main() -> std::io::Result<()> { - /// - /// use std::io::{Write, IoSlice}; - /// - /// let mut writer = Vec::new(); - /// let bufs = &mut [ - /// IoSlice::new(&[1]), - /// IoSlice::new(&[2, 3]), - /// IoSlice::new(&[4, 5, 6]), - /// ]; - /// - /// writer.write_all_vectored(bufs)?; - /// // Note: the contents of `bufs` is now undefined, see the Notes section. - /// - /// assert_eq!(writer, &[1, 2, 3, 4, 5, 6]); - /// # Ok(()) } - /// ``` - #[unstable(feature = "write_all_vectored", issue = "70436")] - fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> { - // Guarantee that bufs is empty if it contains no data, - // to avoid calling write_vectored if there is no data to be written. - IoSlice::advance_slices(&mut bufs, 0); - while !bufs.is_empty() { - match self.write_vectored(bufs) { - Ok(0) => { - return Err(Error::WRITE_ALL_EOF); - } - Ok(n) => IoSlice::advance_slices(&mut bufs, n), - Err(ref e) if e.is_interrupted() => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Writes a formatted string into this writer, returning any error - /// encountered. - /// - /// This method is primarily used to interface with the - /// [`format_args!()`] macro, and it is rare that this should - /// explicitly be called. The [`write!()`] macro should be favored to - /// invoke this method instead. - /// - /// This function internally uses the [`write_all`] method on - /// this trait and hence will continuously write data so long as no errors - /// are received. This also means that partial writes are not indicated in - /// this signature. - /// - /// [`write_all`]: Write::write_all - /// - /// # Errors - /// - /// This function will return any I/O error reported while formatting. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // this call - /// write!(buffer, "{:.*}", 2, 1.234567)?; - /// // turns into this: - /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> { - if let Some(s) = args.as_statically_known_str() { - self.write_all(s.as_bytes()) - } else { - default_write_fmt(self, args) - } - } - - /// Creates a "by reference" adapter for this instance of `Write`. - /// - /// The returned adapter also implements `Write` and will simply borrow this - /// current writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::Write; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// let reference = buffer.by_ref(); - /// - /// // we can use reference just like our original buffer - /// reference.write_all(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn by_ref(&mut self) -> &mut Self - where - Self: Sized, - { - self - } -} - -/// The `Seek` trait provides a cursor which can be moved within a stream of -/// bytes. -/// -/// The stream typically has a fixed size, allowing seeking relative to either -/// end or the current offset. -/// -/// # Examples -/// -/// [`File`]s implement `Seek`: -/// -/// [`File`]: crate::fs::File -/// -/// ```no_run -/// use std::io; -/// use std::io::prelude::*; -/// use std::fs::File; -/// use std::io::SeekFrom; -/// -/// fn main() -> io::Result<()> { -/// let mut f = File::open("foo.txt")?; -/// -/// // move the cursor 42 bytes from the start of the file -/// f.seek(SeekFrom::Start(42))?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "IoSeek")] -pub trait Seek { - /// Seek to an offset, in bytes, in a stream. - /// - /// A seek beyond the end of a stream is allowed, but behavior is defined - /// by the implementation. - /// - /// If the seek operation completed successfully, - /// this method returns the new position from the start of the stream. - /// That position can be used later with [`SeekFrom::Start`]. - /// - /// # Errors - /// - /// Seeking can fail, for example because it might involve flushing a buffer. - /// - /// Seeking to a negative offset is considered an error. - #[stable(feature = "rust1", since = "1.0.0")] - fn seek(&mut self, pos: SeekFrom) -> Result; - - /// Rewind to the beginning of a stream. - /// - /// This is a convenience method, equivalent to `seek(SeekFrom::Start(0))`. - /// - /// # Errors - /// - /// Rewinding can fail, for example because it might involve flushing a buffer. - /// - /// # Example - /// - /// ```no_run - /// use std::io::{Read, Seek, Write}; - /// use std::fs::OpenOptions; - /// - /// let mut f = OpenOptions::new() - /// .write(true) - /// .read(true) - /// .create(true) - /// .open("foo.txt")?; - /// - /// let hello = "Hello!\n"; - /// write!(f, "{hello}")?; - /// f.rewind()?; - /// - /// let mut buf = String::new(); - /// f.read_to_string(&mut buf)?; - /// assert_eq!(&buf, hello); - /// # std::io::Result::Ok(()) - /// ``` - #[stable(feature = "seek_rewind", since = "1.55.0")] - fn rewind(&mut self) -> Result<()> { - self.seek(SeekFrom::Start(0))?; - Ok(()) - } - - /// Returns the length of this stream (in bytes). - /// - /// The default implementation uses up to three seek operations. If this - /// method returns successfully, the seek position is unchanged (i.e. the - /// position before calling this method is the same as afterwards). - /// However, if this method returns an error, the seek position is - /// unspecified. - /// - /// If you need to obtain the length of *many* streams and you don't care - /// about the seek position afterwards, you can reduce the number of seek - /// operations by simply calling `seek(SeekFrom::End(0))` and using its - /// return value (it is also the stream length). - /// - /// Note that length of a stream can change over time (for example, when - /// data is appended to a file). So calling this method multiple times does - /// not necessarily return the same length each time. - /// - /// # Example - /// - /// ```no_run - /// #![feature(seek_stream_len)] - /// use std::{ - /// io::{self, Seek}, - /// fs::File, - /// }; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// - /// let len = f.stream_len()?; - /// println!("The file is currently {len} bytes long"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "seek_stream_len", issue = "59359")] - fn stream_len(&mut self) -> Result { - stream_len_default(self) - } - - /// Returns the current seek position from the start of the stream. - /// - /// This is equivalent to `self.seek(SeekFrom::Current(0))`. - /// - /// # Example - /// - /// ```no_run - /// use std::{ - /// io::{self, BufRead, BufReader, Seek}, - /// fs::File, - /// }; - /// - /// fn main() -> io::Result<()> { - /// let mut f = BufReader::new(File::open("foo.txt")?); - /// - /// let before = f.stream_position()?; - /// f.read_line(&mut String::new())?; - /// let after = f.stream_position()?; - /// - /// println!("The first line was {} bytes long", after - before); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "seek_convenience", since = "1.51.0")] - fn stream_position(&mut self) -> Result { - self.seek(SeekFrom::Current(0)) - } - - /// Seeks relative to the current position. - /// - /// This is equivalent to `self.seek(SeekFrom::Current(offset))` but - /// doesn't return the new position which can allow some implementations - /// such as [`BufReader`] to perform more efficient seeks. - /// - /// # Example - /// - /// ```no_run - /// use std::{ - /// io::{self, Seek}, - /// fs::File, - /// }; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// f.seek_relative(10)?; - /// assert_eq!(f.stream_position()?, 10); - /// Ok(()) - /// } - /// ``` - /// - /// [`BufReader`]: crate::io::BufReader - #[stable(feature = "seek_seek_relative", since = "1.80.0")] - fn seek_relative(&mut self, offset: i64) -> Result<()> { - self.seek(SeekFrom::Current(offset))?; - Ok(()) - } -} - -pub(crate) fn stream_len_default(self_: &mut T) -> Result { - let old_pos = self_.stream_position()?; - let len = self_.seek(SeekFrom::End(0))?; - - // Avoid seeking a third time when we were already at the end of the - // stream. The branch is usually way cheaper than a seek operation. - if old_pos != len { - self_.seek(SeekFrom::Start(old_pos))?; - } - - Ok(len) -} - -/// Enumeration of possible methods to seek within an I/O object. -/// -/// It is used by the [`Seek`] trait. -#[derive(Copy, PartialEq, Eq, Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "SeekFrom")] -pub enum SeekFrom { - /// Sets the offset to the provided number of bytes. - #[stable(feature = "rust1", since = "1.0.0")] - Start(#[stable(feature = "rust1", since = "1.0.0")] u64), - - /// Sets the offset to the size of this object plus the specified number of - /// bytes. - /// - /// It is possible to seek beyond the end of an object, but it's an error to - /// seek before byte 0. - #[stable(feature = "rust1", since = "1.0.0")] - End(#[stable(feature = "rust1", since = "1.0.0")] i64), - - /// Sets the offset to the current position plus the specified number of - /// bytes. - /// - /// It is possible to seek beyond the end of an object, but it's an error to - /// seek before byte 0. - #[stable(feature = "rust1", since = "1.0.0")] - Current(#[stable(feature = "rust1", since = "1.0.0")] i64), -} - -fn read_until(r: &mut R, delim: u8, buf: &mut Vec) -> Result { - let mut read = 0; - loop { - let (done, used) = { - let available = match r.fill_buf() { - Ok(n) => n, - Err(ref e) if e.is_interrupted() => continue, - Err(e) => return Err(e), - }; - match memchr::memchr(delim, available) { - Some(i) => { - buf.extend_from_slice(&available[..=i]); - (true, i + 1) - } - None => { - buf.extend_from_slice(available); - (false, available.len()) - } - } - }; - r.consume(used); - read += used; - if done || used == 0 { - return Ok(read); - } - } -} - -fn skip_until(r: &mut R, delim: u8) -> Result { - let mut read = 0; - loop { - let (done, used) = { - let available = match r.fill_buf() { - Ok(n) => n, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Err(e), - }; - match memchr::memchr(delim, available) { - Some(i) => (true, i + 1), - None => (false, available.len()), - } - }; - r.consume(used); - read += used; - if done || used == 0 { - return Ok(read); - } - } -} - -/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it -/// to perform extra ways of reading. -/// -/// For example, reading line-by-line is inefficient without using a buffer, so -/// if you want to read by line, you'll need `BufRead`, which includes a -/// [`read_line`] method as well as a [`lines`] iterator. -/// -/// # Examples -/// -/// A locked standard input implements `BufRead`: -/// -/// ```no_run -/// use std::io; -/// use std::io::prelude::*; -/// -/// let stdin = io::stdin(); -/// for line in stdin.lock().lines() { -/// println!("{}", line?); -/// } -/// # std::io::Result::Ok(()) -/// ``` -/// -/// If you have something that implements [`Read`], you can use the [`BufReader` -/// type][`BufReader`] to turn it into a `BufRead`. -/// -/// For example, [`File`] implements [`Read`], but not `BufRead`. -/// [`BufReader`] to the rescue! -/// -/// [`File`]: crate::fs::File -/// [`read_line`]: BufRead::read_line -/// [`lines`]: BufRead::lines -/// -/// ```no_run -/// use std::io::{self, BufReader}; -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// fn main() -> io::Result<()> { -/// let f = File::open("foo.txt")?; -/// let f = BufReader::new(f); -/// -/// for line in f.lines() { -/// let line = line?; -/// println!("{line}"); -/// } -/// -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "IoBufRead")] -pub trait BufRead: Read { - /// Returns the contents of the internal buffer, filling it with more data, via `Read` methods, if empty. - /// - /// This is a lower-level method and is meant to be used together with [`consume`], - /// which can be used to mark bytes that should not be returned by subsequent calls to `read`. - /// - /// [`consume`]: BufRead::consume - /// - /// Returns an empty buffer when the stream has reached EOF. - /// - /// # Errors - /// - /// This function will return an I/O error if a `Read` method was called, but returned an error. - /// - /// # Examples - /// - /// A locked standard input implements `BufRead`: - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// - /// let buffer = stdin.fill_buf()?; - /// - /// // work with buffer - /// println!("{buffer:?}"); - /// - /// // mark the bytes we worked with as read - /// let length = buffer.len(); - /// stdin.consume(length); - /// # std::io::Result::Ok(()) - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn fill_buf(&mut self) -> Result<&[u8]>; - - /// Marks the given `amount` of additional bytes from the internal buffer as having been read. - /// Subsequent calls to `read` only return bytes that have not been marked as read. - /// - /// This is a lower-level method and is meant to be used together with [`fill_buf`], - /// which can be used to fill the internal buffer via `Read` methods. - /// - /// It is a logic error if `amount` exceeds the number of unread bytes in the internal buffer, which is returned by [`fill_buf`]. - /// - /// # Examples - /// - /// Since `consume()` is meant to be used with [`fill_buf`], - /// that method's example includes an example of `consume()`. - /// - /// [`fill_buf`]: BufRead::fill_buf - #[stable(feature = "rust1", since = "1.0.0")] - fn consume(&mut self, amount: usize); - - /// Checks if there is any data left to be `read`. - /// - /// This function may fill the buffer to check for data, - /// so this function returns `Result`, not `bool`. - /// - /// The default implementation calls `fill_buf` and checks that the - /// returned slice is empty (which means that there is no data left, - /// since EOF is reached). - /// - /// # Errors - /// - /// This function will return an I/O error if a `Read` method was called, but returned an error. - /// - /// Examples - /// - /// ``` - /// #![feature(buf_read_has_data_left)] - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// - /// while stdin.has_data_left()? { - /// let mut line = String::new(); - /// stdin.read_line(&mut line)?; - /// // work with line - /// println!("{line:?}"); - /// } - /// # std::io::Result::Ok(()) - /// ``` - #[unstable(feature = "buf_read_has_data_left", issue = "86423")] - fn has_data_left(&mut self) -> Result { - self.fill_buf().map(|b| !b.is_empty()) - } - - /// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. - /// - /// This function will read bytes from the underlying stream until the - /// delimiter or EOF is found. Once found, all bytes up to, and including, - /// the delimiter (if found) will be appended to `buf`. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// This function is blocking and should be used carefully: it is possible for - /// an attacker to continuously send bytes without ever sending the delimiter - /// or EOF. - /// - /// # Errors - /// - /// This function will ignore all instances of [`ErrorKind::Interrupted`] and - /// will otherwise return any errors returned by [`fill_buf`]. - /// - /// If an I/O error is encountered then all bytes read so far will be - /// present in `buf` and its length will have been adjusted appropriately. - /// - /// [`fill_buf`]: BufRead::fill_buf - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to read all the bytes in a byte slice - /// in hyphen delimited segments: - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let mut cursor = io::Cursor::new(b"lorem-ipsum"); - /// let mut buf = vec![]; - /// - /// // cursor is at 'l' - /// let num_bytes = cursor.read_until(b'-', &mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 6); - /// assert_eq!(buf, b"lorem-"); - /// buf.clear(); - /// - /// // cursor is at 'i' - /// let num_bytes = cursor.read_until(b'-', &mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 5); - /// assert_eq!(buf, b"ipsum"); - /// buf.clear(); - /// - /// // cursor is at EOF - /// let num_bytes = cursor.read_until(b'-', &mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 0); - /// assert_eq!(buf, b""); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { - read_until(self, byte, buf) - } - - /// Skips all bytes until the delimiter `byte` or EOF is reached. - /// - /// This function will read (and discard) bytes from the underlying stream until the - /// delimiter or EOF is found. - /// - /// If successful, this function will return the total number of bytes read, - /// including the delimiter byte if found. - /// - /// This is useful for efficiently skipping data such as NUL-terminated strings - /// in binary file formats without buffering. - /// - /// This function is blocking and should be used carefully: it is possible for - /// an attacker to continuously send bytes without ever sending the delimiter - /// or EOF. - /// - /// # Errors - /// - /// This function will ignore all instances of [`ErrorKind::Interrupted`] and - /// will otherwise return any errors returned by [`fill_buf`]. - /// - /// If an I/O error is encountered then all bytes read so far will be - /// present in `buf` and its length will have been adjusted appropriately. - /// - /// [`fill_buf`]: BufRead::fill_buf - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to read some NUL-terminated information - /// about Ferris from a binary string, skipping the fun fact: - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0!"); - /// - /// // read name - /// let mut name = Vec::new(); - /// let num_bytes = cursor.read_until(b'\0', &mut name) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 7); - /// assert_eq!(name, b"Ferris\0"); - /// - /// // skip fun fact - /// let num_bytes = cursor.skip_until(b'\0') - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 30); - /// - /// // read animal type - /// let mut animal = Vec::new(); - /// let num_bytes = cursor.read_until(b'\0', &mut animal) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 11); - /// assert_eq!(animal, b"Crustacean\0"); - /// - /// // reach EOF - /// let num_bytes = cursor.skip_until(b'\0') - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 1); - /// ``` - #[stable(feature = "bufread_skip_until", since = "1.83.0")] - fn skip_until(&mut self, byte: u8) -> Result { - skip_until(self, byte) - } - - /// Reads all bytes until a newline (the `0xA` byte) is reached, and append - /// them to the provided `String` buffer. - /// - /// Previous content of the buffer will be preserved. To avoid appending to - /// the buffer, you need to [`clear`] it first. - /// - /// This function will read bytes from the underlying stream until the - /// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes - /// up to, and including, the delimiter (if found) will be appended to - /// `buf`. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// If this function returns [`Ok(0)`], the stream has reached EOF. - /// - /// This function is blocking and should be used carefully: it is possible for - /// an attacker to continuously send bytes without ever sending a newline - /// or EOF. You can use [`take`] to limit the maximum number of bytes read. - /// - /// [`Ok(0)`]: Ok - /// [`clear`]: String::clear - /// [`take`]: crate::io::Read::take - /// - /// # Errors - /// - /// This function has the same error semantics as [`read_until`] and will - /// also return an error if the read bytes are not valid UTF-8. If an I/O - /// error is encountered then `buf` may contain some bytes already read in - /// the event that all data read so far was valid UTF-8. - /// - /// [`read_until`]: BufRead::read_until - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to read all the lines in a byte slice: - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let mut cursor = io::Cursor::new(b"foo\nbar"); - /// let mut buf = String::new(); - /// - /// // cursor is at 'f' - /// let num_bytes = cursor.read_line(&mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 4); - /// assert_eq!(buf, "foo\n"); - /// buf.clear(); - /// - /// // cursor is at 'b' - /// let num_bytes = cursor.read_line(&mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 3); - /// assert_eq!(buf, "bar"); - /// buf.clear(); - /// - /// // cursor is at EOF - /// let num_bytes = cursor.read_line(&mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 0); - /// assert_eq!(buf, ""); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn read_line(&mut self, buf: &mut String) -> Result { - // Note that we are not calling the `.read_until` method here, but - // rather our hardcoded implementation. For more details as to why, see - // the comments in `default_read_to_string`. - unsafe { append_to_string(buf, |b| read_until(self, b'\n', b)) } - } - - /// Returns an iterator over the contents of this reader split on the byte - /// `byte`. - /// - /// The iterator returned from this function will return instances of - /// [io::Result]<[Vec]\>. Each vector returned will *not* have - /// the delimiter byte at the end. - /// - /// This function will yield errors whenever [`read_until`] would have - /// also yielded an error. - /// - /// [io::Result]: self::Result "io::Result" - /// [`read_until`]: BufRead::read_until - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to iterate over all hyphen delimited - /// segments in a byte slice - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor"); - /// - /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap()); - /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec())); - /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec())); - /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec())); - /// assert_eq!(split_iter.next(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn split(self, byte: u8) -> Split - where - Self: Sized, - { - Split { buf: self, delim: byte } - } - - /// Returns an iterator over the lines of this reader. - /// - /// The iterator returned from this function will yield instances of - /// [io::Result]<[String]>. Each string returned will *not* have a newline - /// byte (the `0xA` byte) or `CRLF` (`0xD`, `0xA` bytes) at the end. - /// - /// [io::Result]: self::Result "io::Result" - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to iterate over all the lines in a byte - /// slice. - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); - /// - /// let mut lines_iter = cursor.lines().map(|l| l.unwrap()); - /// assert_eq!(lines_iter.next(), Some(String::from("lorem"))); - /// assert_eq!(lines_iter.next(), Some(String::from("ipsum"))); - /// assert_eq!(lines_iter.next(), Some(String::from("dolor"))); - /// assert_eq!(lines_iter.next(), None); - /// ``` - /// - /// # Errors - /// - /// Each line of the iterator has the same error semantics as [`BufRead::read_line`]. - #[stable(feature = "rust1", since = "1.0.0")] - fn lines(self) -> Lines - where - Self: Sized, - { - Lines { buf: self } - } -} - -/// Adapter to chain together two readers. -/// -/// This struct is generally created by calling [`chain`] on a reader. -/// Please see the documentation of [`chain`] for more details. -/// -/// [`chain`]: Read::chain -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Chain { - first: T, - second: U, - done_first: bool, -} - -impl Chain { - /// Consumes the `Chain`, returning the wrapped readers. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; - /// - /// let chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.into_inner(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn into_inner(self) -> (T, U) { - (self.first, self.second) - } - - /// Gets references to the underlying readers in this `Chain`. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying readers as doing so may corrupt the internal state of this - /// `Chain`. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; - /// - /// let chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn get_ref(&self) -> (&T, &U) { - (&self.first, &self.second) - } - - /// Gets mutable references to the underlying readers in this `Chain`. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying readers as doing so may corrupt the internal state of this - /// `Chain`. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; - /// - /// let mut chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn get_mut(&mut self) -> (&mut T, &mut U) { - (&mut self.first, &mut self.second) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Chain { - fn read(&mut self, buf: &mut [u8]) -> Result { - if !self.done_first { - match self.first.read(buf)? { - 0 if !buf.is_empty() => self.done_first = true, - n => return Ok(n), - } - } - self.second.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - if !self.done_first { - match self.first.read_vectored(bufs)? { - 0 if bufs.iter().any(|b| !b.is_empty()) => self.done_first = true, - n => return Ok(n), - } - } - self.second.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.first.is_read_vectored() || self.second.is_read_vectored() - } - - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - let mut read = 0; - if !self.done_first { - read += self.first.read_to_end(buf)?; - self.done_first = true; - } - read += self.second.read_to_end(buf)?; - Ok(read) - } - - // We don't override `read_to_string` here because an UTF-8 sequence could - // be split between the two parts of the chain - - fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { - if buf.capacity() == 0 { - return Ok(()); - } - - if !self.done_first { - let old_len = buf.written(); - self.first.read_buf(buf.reborrow())?; - - if buf.written() != old_len { - return Ok(()); - } else { - self.done_first = true; - } - } - self.second.read_buf(buf) - } -} - -#[stable(feature = "chain_bufread", since = "1.9.0")] -impl BufRead for Chain { - fn fill_buf(&mut self) -> Result<&[u8]> { - if !self.done_first { - match self.first.fill_buf()? { - buf if buf.is_empty() => self.done_first = true, - buf => return Ok(buf), - } - } - self.second.fill_buf() - } - - fn consume(&mut self, amt: usize) { - if !self.done_first { self.first.consume(amt) } else { self.second.consume(amt) } - } - - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { - let mut read = 0; - if !self.done_first { - let n = self.first.read_until(byte, buf)?; - read += n; - - match buf.last() { - Some(b) if *b == byte && n != 0 => return Ok(read), - _ => self.done_first = true, - } - } - read += self.second.read_until(byte, buf)?; - Ok(read) - } - - // We don't override `read_line` here because an UTF-8 sequence could be - // split between the two parts of the chain -} - -impl SizeHint for Chain { - #[inline] - fn lower_bound(&self) -> usize { - SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) - } - - #[inline] - fn upper_bound(&self) -> Option { - match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { - (Some(first), Some(second)) => first.checked_add(second), - _ => None, - } - } -} - -/// Reader adapter which limits the bytes read from an underlying reader. -/// -/// This struct is generally created by calling [`take`] on a reader. -/// Please see the documentation of [`take`] for more details. -/// -/// [`take`]: Read::take -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Take { - inner: T, - len: u64, - limit: u64, -} - -impl Take { - /// Returns the number of bytes that can be read before this instance will - /// return EOF. - /// - /// # Note - /// - /// This instance may reach `EOF` after reading fewer bytes than indicated by - /// this method if the underlying [`Read`] instance reaches EOF. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let f = File::open("foo.txt")?; - /// - /// // read at most five bytes - /// let handle = f.take(5); - /// - /// println!("limit: {}", handle.limit()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn limit(&self) -> u64 { - self.limit - } - - /// Returns the number of bytes read so far. - #[unstable(feature = "seek_io_take_position", issue = "97227")] - pub fn position(&self) -> u64 { - self.len - self.limit - } - - /// Sets the number of bytes that can be read before this instance will - /// return EOF. This is the same as constructing a new `Take` instance, so - /// the amount of bytes read and the previous limit value don't matter when - /// calling this method. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let f = File::open("foo.txt")?; - /// - /// // read at most five bytes - /// let mut handle = f.take(5); - /// handle.set_limit(10); - /// - /// assert_eq!(handle.limit(), 10); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "take_set_limit", since = "1.27.0")] - pub fn set_limit(&mut self, limit: u64) { - self.len = limit; - self.limit = limit; - } - - /// Consumes the `Take`, returning the wrapped reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; - /// - /// let file = handle.into_inner(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "io_take_into_inner", since = "1.15.0")] - pub fn into_inner(self) -> T { - self.inner - } - - /// Gets a reference to the underlying reader. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying reader as doing so may corrupt the internal limit of this - /// `Take`. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; - /// - /// let file = handle.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Gets a mutable reference to the underlying reader. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying reader as doing so may corrupt the internal limit of this - /// `Take`. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; - /// - /// let file = handle.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Take { - fn read(&mut self, buf: &mut [u8]) -> Result { - // Don't call into inner reader at all at EOF because it may still block - if self.limit == 0 { - return Ok(0); - } - - let max = cmp::min(buf.len() as u64, self.limit) as usize; - let n = self.inner.read(&mut buf[..max])?; - assert!(n as u64 <= self.limit, "number of read bytes exceeds limit"); - self.limit -= n as u64; - Ok(n) - } - - fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { - // Don't call into inner reader at all at EOF because it may still block - if self.limit == 0 { - return Ok(()); - } - - if self.limit < buf.capacity() as u64 { - // The condition above guarantees that `self.limit` fits in `usize`. - let limit = self.limit as usize; - - let extra_init = cmp::min(limit, buf.init_mut().len()); - - // SAFETY: no uninit data is written to ibuf - let ibuf = unsafe { &mut buf.as_mut()[..limit] }; - - let mut sliced_buf: BorrowedBuf<'_> = ibuf.into(); - - // SAFETY: extra_init bytes of ibuf are known to be initialized - unsafe { - sliced_buf.set_init(extra_init); - } - - let mut cursor = sliced_buf.unfilled(); - let result = self.inner.read_buf(cursor.reborrow()); - - let new_init = cursor.init_mut().len(); - let filled = sliced_buf.len(); - - // cursor / sliced_buf / ibuf must drop here - - unsafe { - // SAFETY: filled bytes have been filled and therefore initialized - buf.advance_unchecked(filled); - // SAFETY: new_init bytes of buf's unfilled buffer have been initialized - buf.set_init(new_init); - } - - self.limit -= filled as u64; - - result - } else { - let written = buf.written(); - let result = self.inner.read_buf(buf.reborrow()); - self.limit -= (buf.written() - written) as u64; - result - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for Take { - fn fill_buf(&mut self) -> Result<&[u8]> { - // Don't call into inner reader at all at EOF because it may still block - if self.limit == 0 { - return Ok(&[]); - } - - let buf = self.inner.fill_buf()?; - let cap = cmp::min(buf.len() as u64, self.limit) as usize; - Ok(&buf[..cap]) - } - - fn consume(&mut self, amt: usize) { - // Don't let callers reset the limit by passing an overlarge value - let amt = cmp::min(amt as u64, self.limit) as usize; - self.limit -= amt as u64; - self.inner.consume(amt); - } -} - -impl SizeHint for Take { - #[inline] - fn lower_bound(&self) -> usize { - cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize - } - - #[inline] - fn upper_bound(&self) -> Option { - match SizeHint::upper_bound(&self.inner) { - Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize), - None => self.limit.try_into().ok(), - } - } -} - -#[stable(feature = "seek_io_take", since = "1.89.0")] -impl Seek for Take { - fn seek(&mut self, pos: SeekFrom) -> Result { - let new_position = match pos { - SeekFrom::Start(v) => Some(v), - SeekFrom::Current(v) => self.position().checked_add_signed(v), - SeekFrom::End(v) => self.len.checked_add_signed(v), - }; - let new_position = match new_position { - Some(v) if v <= self.len => v, - _ => return Err(ErrorKind::InvalidInput.into()), - }; - while new_position != self.position() { - if let Some(offset) = new_position.checked_signed_diff(self.position()) { - self.inner.seek_relative(offset)?; - self.limit = self.limit.wrapping_sub(offset as u64); - break; - } - let offset = if new_position > self.position() { i64::MAX } else { i64::MIN }; - self.inner.seek_relative(offset)?; - self.limit = self.limit.wrapping_sub(offset as u64); - } - Ok(new_position) - } - - fn stream_len(&mut self) -> Result { - Ok(self.len) - } - - fn stream_position(&mut self) -> Result { - Ok(self.position()) - } - - fn seek_relative(&mut self, offset: i64) -> Result<()> { - if !self.position().checked_add_signed(offset).is_some_and(|p| p <= self.len) { - return Err(ErrorKind::InvalidInput.into()); - } - self.inner.seek_relative(offset)?; - self.limit = self.limit.wrapping_sub(offset as u64); - Ok(()) - } -} - -/// An iterator over `u8` values of a reader. -/// -/// This struct is generally created by calling [`bytes`] on a reader. -/// Please see the documentation of [`bytes`] for more details. -/// -/// [`bytes`]: Read::bytes -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Bytes { - inner: R, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Bytes { - type Item = Result; - - // Not `#[inline]`. This function gets inlined even without it, but having - // the inline annotation can result in worse code generation. See #116785. - fn next(&mut self) -> Option> { - SpecReadByte::spec_read_byte(&mut self.inner) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - SizeHint::size_hint(&self.inner) - } -} - -/// For the specialization of `Bytes::next`. -trait SpecReadByte { - fn spec_read_byte(&mut self) -> Option>; -} - -impl SpecReadByte for R -where - Self: Read, -{ - #[inline] - default fn spec_read_byte(&mut self) -> Option> { - inlined_slow_read_byte(self) - } -} - -/// Reads a single byte in a slow, generic way. This is used by the default -/// `spec_read_byte`. -#[inline] -fn inlined_slow_read_byte(reader: &mut R) -> Option> { - let mut byte = 0; - loop { - return match reader.read(slice::from_mut(&mut byte)) { - Ok(0) => None, - Ok(..) => Some(Ok(byte)), - Err(ref e) if e.is_interrupted() => continue, - Err(e) => Some(Err(e)), - }; - } -} - -// Used by `BufReader::spec_read_byte`, for which the `inline(never)` is -// important. -#[inline(never)] -fn uninlined_slow_read_byte(reader: &mut R) -> Option> { - inlined_slow_read_byte(reader) -} - -trait SizeHint { - fn lower_bound(&self) -> usize; - - fn upper_bound(&self) -> Option; - - fn size_hint(&self) -> (usize, Option) { - (self.lower_bound(), self.upper_bound()) - } -} - -impl SizeHint for T { - #[inline] - default fn lower_bound(&self) -> usize { - 0 - } - - #[inline] - default fn upper_bound(&self) -> Option { - None - } -} - -impl SizeHint for &mut T { - #[inline] - fn lower_bound(&self) -> usize { - SizeHint::lower_bound(*self) - } - - #[inline] - fn upper_bound(&self) -> Option { - SizeHint::upper_bound(*self) - } -} - -impl SizeHint for Box { - #[inline] - fn lower_bound(&self) -> usize { - SizeHint::lower_bound(&**self) - } - - #[inline] - fn upper_bound(&self) -> Option { - SizeHint::upper_bound(&**self) - } -} - -impl SizeHint for &[u8] { - #[inline] - fn lower_bound(&self) -> usize { - self.len() - } - - #[inline] - fn upper_bound(&self) -> Option { - Some(self.len()) - } -} - -/// An iterator over the contents of an instance of `BufRead` split on a -/// particular byte. -/// -/// This struct is generally created by calling [`split`] on a `BufRead`. -/// Please see the documentation of [`split`] for more details. -/// -/// [`split`]: BufRead::split -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -#[cfg_attr(not(test), rustc_diagnostic_item = "IoSplit")] -pub struct Split { - buf: B, - delim: u8, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Split { - type Item = Result>; - - fn next(&mut self) -> Option>> { - let mut buf = Vec::new(); - match self.buf.read_until(self.delim, &mut buf) { - Ok(0) => None, - Ok(_n) => { - if buf[buf.len() - 1] == self.delim { - buf.pop(); - } - Some(Ok(buf)) - } - Err(e) => Some(Err(e)), - } - } -} - -/// An iterator over the lines of an instance of `BufRead`. -/// -/// This struct is generally created by calling [`lines`] on a `BufRead`. -/// Please see the documentation of [`lines`] for more details. -/// -/// [`lines`]: BufRead::lines -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -#[cfg_attr(not(test), rustc_diagnostic_item = "IoLines")] -pub struct Lines { - buf: B, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Lines { - type Item = Result; - - fn next(&mut self) -> Option> { - let mut buf = String::new(); - match self.buf.read_line(&mut buf) { - Ok(0) => None, - Ok(_n) => { - if buf.ends_with('\n') { - buf.pop(); - if buf.ends_with('\r') { - buf.pop(); - } - } - Some(Ok(buf)) - } - Err(e) => Some(Err(e)), - } - } -} +#[cfg(test)] +mod io_benches; diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 2d80fe49e80a7..8cfda7e9bc597 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -543,6 +543,7 @@ impl Read for StdinLock<'_> { } } +#[unstable(feature = "io_internals", issue = "none")] impl SpecReadByte for StdinLock<'_> { #[inline] fn spec_read_byte(&mut self) -> Option> { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 70ccd3431a2ff..da46a9636c44e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -371,15 +371,27 @@ // // Library features (alloc): // tidy-alphabetical-start +#![feature(alloc_io)] #![feature(allocator_api)] +#![feature(can_vector)] #![feature(clone_from_ref)] #![feature(get_mut_unchecked)] +#![feature(io_error_inprogress)] +#![feature(io_error_internals)] +#![feature(io_error_more)] +#![feature(io_error_uncategorized)] +#![feature(io_internals)] +#![feature(io_slice_as_bytes)] #![feature(map_try_insert)] +#![feature(raw_os_error_ty)] +#![feature(read_buf)] +#![feature(seek_stream_len)] #![feature(slice_concat_trait)] #![feature(thin_box)] #![feature(try_reserve_kind)] #![feature(try_with_capacity)] #![feature(unique_rc_arc)] +#![feature(write_all_vectored)] #![feature(wtf8_internals)] // tidy-alphabetical-end // diff --git a/library/std/src/sys/io/error/mod.rs b/library/std/src/sys/io/error/mod.rs index d7a0b9b4b301d..4fca658a7dcaa 100644 --- a/library/std/src/sys/io/error/mod.rs +++ b/library/std/src/sys/io/error/mod.rs @@ -48,8 +48,3 @@ cfg_select! { pub use generic::*; } } - -pub type RawOsError = cfg_select! { - target_os = "uefi" => usize, - _ => i32, -}; diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs index b3587ab63696a..41fa786ad895b 100644 --- a/library/std/src/sys/io/mod.rs +++ b/library/std/src/sys/io/mod.rs @@ -2,27 +2,6 @@ mod error; -mod io_slice { - cfg_select! { - any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => { - mod iovec; - pub use iovec::*; - } - target_os = "windows" => { - mod windows; - pub use windows::*; - } - target_os = "uefi" => { - mod uefi; - pub use uefi::*; - } - _ => { - mod unsupported; - pub use unsupported::*; - } - } -} - mod is_terminal { cfg_select! { any(target_family = "unix", target_os = "wasi") => { @@ -62,11 +41,6 @@ pub use error::errno_location; target_os = "wasi", ))] pub use error::set_errno; -pub use error::{RawOsError, decode_error_kind, errno, error_string, is_interrupted}; -pub use io_slice::{IoSlice, IoSliceMut}; +pub use error::{decode_error_kind, errno, error_string, is_interrupted}; pub use is_terminal::is_terminal; pub use kernel_copy::{CopyState, kernel_copy}; - -// Bare metal platforms usually have very small amounts of RAM -// (in the order of hundreds of KB) -pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 }; diff --git a/library/std/src/sys/stdio/motor.rs b/library/std/src/sys/stdio/motor.rs index 2b1bc15285f9c..838fab8fb335f 100644 --- a/library/std/src/sys/stdio/motor.rs +++ b/library/std/src/sys/stdio/motor.rs @@ -2,7 +2,7 @@ use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, Ra use crate::sys::{AsInner, FromInner, IntoInner, map_motor_error}; use crate::{io, process, sys}; -pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; +pub const STDIN_BUF_SIZE: usize = alloc::io::DEFAULT_BUF_SIZE; pub struct Stdin {} diff --git a/library/std/src/sys/stdio/sgx.rs b/library/std/src/sys/stdio/sgx.rs index 2cf47f4919209..684f41eb82392 100644 --- a/library/std/src/sys/stdio/sgx.rs +++ b/library/std/src/sys/stdio/sgx.rs @@ -89,7 +89,7 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; +pub const STDIN_BUF_SIZE: usize = alloc::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { // FIXME: Rust normally maps Unix EBADF to `Uncategorized` diff --git a/library/std/src/sys/stdio/unix.rs b/library/std/src/sys/stdio/unix.rs index ffed376a8e96e..c5304729e6b63 100644 --- a/library/std/src/sys/stdio/unix.rs +++ b/library/std/src/sys/stdio/unix.rs @@ -93,7 +93,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { err.raw_os_error() == Some(EBADF as i32) } -pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; +pub const STDIN_BUF_SIZE: usize = alloc::io::DEFAULT_BUF_SIZE; pub fn panic_output() -> Option { Some(Stderr::new()) diff --git a/library/std/src/sys/stdio/zkvm.rs b/library/std/src/sys/stdio/zkvm.rs index f31c6c26e87cd..b7f201e640abc 100644 --- a/library/std/src/sys/stdio/zkvm.rs +++ b/library/std/src/sys/stdio/zkvm.rs @@ -61,7 +61,7 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; +pub const STDIN_BUF_SIZE: usize = alloc::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(_err: &io::Error) -> bool { true diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index e07a0784cdb3a..44a232bcc4216 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -51,6 +51,8 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ ("alloc/slice/trait.Concat.html", &["#method.concat"]), ("alloc/slice/index.html", &["#method.concat", "#method.join"]), ("alloc/vec/struct.Vec.html", &["#method.sort_by_key", "#method.sort_by_cached_key"]), + ("alloc/io/struct.IoSlice.html", &["#method.sort_by_key"]), + ("alloc/io/struct.IoSliceMut.html", &["#method.sort_by_key"]), ("alloc/bstr/struct.ByteStr.html", &[ "#method.to_ascii_uppercase", "#method.to_ascii_lowercase", diff --git a/tests/rustdoc-html/intra-doc/deprecated.rs b/tests/rustdoc-html/intra-doc/deprecated.rs index 6f8639593a2d4..86be33fe80cdc 100644 --- a/tests/rustdoc-html/intra-doc/deprecated.rs +++ b/tests/rustdoc-html/intra-doc/deprecated.rs @@ -1,6 +1,6 @@ //@ has deprecated/struct.A.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' -//@ has deprecated/struct.B1.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' -//@ has deprecated/struct.B2.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has deprecated/struct.B1.html '//a[@href="{{channel}}/alloc/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has deprecated/struct.B2.html '//a[@href="{{channel}}/alloc/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' #[deprecated = "[start][std::ops::Range::start]"] pub struct A; diff --git a/tests/rustdoc-html/intra-doc/field.rs b/tests/rustdoc-html/intra-doc/field.rs index e98419618e23f..ba8f09bc90510 100644 --- a/tests/rustdoc-html/intra-doc/field.rs +++ b/tests/rustdoc-html/intra-doc/field.rs @@ -1,5 +1,5 @@ //@ has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' -//@ has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has field/index.html '//a[@href="{{channel}}/alloc/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' //@ has field/index.html '//a[@href="struct.FieldAndMethod.html#structfield.x"]' 'x' //@ has field/index.html '//a[@href="enum.VariantAndMethod.html#variant.X"]' 'X' //! [start][std::ops::Range::start] diff --git a/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr index a997fbee1f2a0..6ce86680c6fe8 100644 --- a/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr +++ b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr @@ -12,7 +12,7 @@ note: an implementation of `PartialEq` might be missing for `T1` LL | struct T1; | ^^^^^^^^^ must implement `PartialEq` note: `std::io::Error` does not implement `PartialEq` - --> $SRC_DIR/std/src/io/error.rs:LL:COL + --> $SRC_DIR/alloc/src/io/error.rs:LL:COL | = note: `std::io::Error` is defined in another crate help: consider annotating `T1` with `#[derive(PartialEq)]` @@ -34,7 +34,7 @@ note: `Thread` does not implement `PartialEq` | = note: `Thread` is defined in another crate note: `std::io::Error` does not implement `PartialEq` - --> $SRC_DIR/std/src/io/error.rs:LL:COL + --> $SRC_DIR/alloc/src/io/error.rs:LL:COL | = note: `std::io::Error` is defined in another crate @@ -58,7 +58,7 @@ note: `Thread` does not implement `PartialEq` | = note: `Thread` is defined in another crate note: `std::io::Error` does not implement `PartialEq` - --> $SRC_DIR/std/src/io/error.rs:LL:COL + --> $SRC_DIR/alloc/src/io/error.rs:LL:COL | = note: `std::io::Error` is defined in another crate help: consider annotating `T1` with `#[derive(PartialEq)]`