Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
fce1e6d
Make `std::sys::io::io_slice` compatible with `core`
bushrat011899 May 13, 2026
f55be48
Move `std::io::IoSlice(Mut)` to `core::io`
bushrat011899 May 13, 2026
0df25ca
Move `IoSlice(Mut)` tests from `std` to `coretests`
bushrat011899 May 13, 2026
d83b24f
Adjust `std::io::Error` tests to only assess public API
bushrat011899 Apr 22, 2026
3e82236
Adjust `Error` documentation
bushrat011899 Apr 22, 2026
6087af8
Change `repr` module definition to use `path` attribute
bushrat011899 May 18, 2026
467fa20
Setup `alloc::io`
bushrat011899 Apr 22, 2026
e93344d
Make common `Error` constants public and hidden
bushrat011899 May 18, 2026
fcaebc4
Allow use of incoherence
bushrat011899 May 18, 2026
fb5e961
Make `Error::is_interrupted` public and hidden
bushrat011899 May 18, 2026
df123ba
Remove usage of `Box` from `Error` internals
bushrat011899 May 18, 2026
b9722ea
Delegate `RawOsError` functionality to `OsFunctions`
bushrat011899 May 18, 2026
626d620
Move `std::io::Error` and friends into `core` and `alloc`
bushrat011899 May 18, 2026
8ee8256
Reduce usage of unstable public items
bushrat011899 May 18, 2026
ce01ff7
Simplify `core::io` documentation links
bushrat011899 May 18, 2026
12bdc4e
Move `std::io::IoHandle` to `core::io`
bushrat011899 May 12, 2026
5e5d4c8
Move `std::io::SizeHint` to `core::io`
bushrat011899 May 12, 2026
2d9ccbb
Move `std::io::SeekFrom` to `core::io`
bushrat011899 May 21, 2026
e848e5d
Move `std::io::Seek` to `core::io`
bushrat011899 May 21, 2026
cf5ae8d
Fix documentation links to `Seek`
bushrat011899 May 22, 2026
89b3d0e
Add `std::io::cursor::WriteThroughCursor`
bushrat011899 May 12, 2026
90b7659
Move `std::io::default_write_vectored` to `core::io`
bushrat011899 May 21, 2026
2c688c4
Move `std::io::cursor::slice_write` to `core::io`
bushrat011899 May 22, 2026
439e412
Move `std::io::cursor::slice_write_vectored` to `core::io`
bushrat011899 May 22, 2026
8abd0c6
Move `std::io::cursor::slice_write_all` to `core::io`
bushrat011899 May 22, 2026
dbb7474
Move `std::io::cursor::slice_write_all_vectored` to `core::io`
bushrat011899 May 22, 2026
13a319e
Move `std::io::Write` to `core::io`
bushrat011899 May 21, 2026
f867438
Fix documentation links to `Write`
bushrat011899 May 22, 2026
55033fe
Move `std::io::Read` internals to `alloc::io`
bushrat011899 May 21, 2026
770e68f
Move `std::io::append_to_string` to `alloc::io`
bushrat011899 May 21, 2026
7eb82b2
Move `std::io::Read` to `alloc::io`
bushrat011899 May 21, 2026
abc68c7
Move `std::io::read_to_string` to `alloc::io`
bushrat011899 May 12, 2026
98ea753
Move `std::io::BufRead` to `alloc::io`
bushrat011899 May 21, 2026
557c4d8
Fix documentation links to `BufRead`
bushrat011899 May 22, 2026
609cb01
Move `std::io::buffered` to `alloc::io`
bushrat011899 May 12, 2026
5c9012e
Move `std::io::copy` internals to `alloc::io`
bushrat011899 May 12, 2026
d4d2511
Setup `core::io::prelude`
bushrat011899 May 21, 2026
9191219
Setup `alloc::io::prelude`
bushrat011899 May 21, 2026
aca38b3
Reduce visibility of unstable internal items
bushrat011899 May 22, 2026
3794559
Move general IO tests to `alloctests`
bushrat011899 May 21, 2026
52b9eb3
Move `std::io::util` tests to `alloctests`
bushrat011899 May 21, 2026
5fcf402
Move `std::io::cursor` tests to `alloctests`
bushrat011899 May 21, 2026
73f4335
Move `std::io::buffered` tests to `alloctests`
bushrat011899 May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
496 changes: 496 additions & 0 deletions library/alloc/src/io/buf_read.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
mod buffer;

use buffer::Buffer;
pub(super) use buffer::Buffer;

use crate::fmt;
use crate::io::{
self, BorrowedCursor, BufRead, DEFAULT_BUF_SIZE, IoSliceMut, Read, Seek, SeekFrom, SizeHint,
SpecReadByte, uninlined_slow_read_byte,
};
use crate::string::String;
use crate::vec::Vec;

/// The `BufReader<R>` struct adds buffering to any reader.
///
Expand All @@ -27,8 +29,8 @@ use crate::io::{
/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause
/// data loss.
///
/// [`TcpStream::read`]: crate::net::TcpStream::read
/// [`TcpStream`]: crate::net::TcpStream
/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
///
/// # Examples
///
Expand Down Expand Up @@ -70,16 +72,21 @@ impl<R: Read> BufReader<R> {
/// Ok(())
/// }
/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(inner: R) -> BufReader<R> {
BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
}

pub(crate) fn try_new_buffer() -> io::Result<Buffer> {
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub fn try_new_buffer() -> io::Result<Buffer> {
Buffer::try_with_capacity(DEFAULT_BUF_SIZE)
}

pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self {
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub fn with_buffer(inner: R, buf: Buffer) -> Self {
Self { inner, buf }
}

Expand All @@ -99,6 +106,7 @@ impl<R: Read> BufReader<R> {
/// Ok(())
/// }
/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
BufReader { inner, buf: Buffer::with_capacity(capacity) }
Expand Down Expand Up @@ -280,14 +288,17 @@ impl<R: ?Sized> BufReader<R> {

/// Invalidates all data in the internal buffer.
#[inline]
pub(in crate::io) fn discard_buffer(&mut self) {
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub fn discard_buffer(&mut self) {
self.buf.discard_buffer()
}
}

// This is only used by a test which asserts that the initialization-tracking is correct.
#[cfg(test)]
impl<R: ?Sized> BufReader<R> {
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
#[allow(missing_docs)]
pub fn initialized(&self) -> bool {
self.buf.initialized()
Expand Down Expand Up @@ -318,6 +329,8 @@ impl<R: ?Sized + Seek> BufReader<R> {
}
}

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl<R> SpecReadByte for BufReader<R>
where
Self: Read,
Expand Down Expand Up @@ -411,7 +424,28 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
let inner_buf = self.buffer();
buf.try_reserve(inner_buf.len())?;
buf.extend_from_slice(inner_buf);

cfg_select! {
no_global_oom_handling => {
// SAFETY:
// * inner_buf and buf are non-overlapping
// * buf[..len] is already initialized
// * buf[len..len + count] is initialized by copy_nonoverlapping
// * len + count is within the capacity of buf based on the reservation completed above
unsafe {
let count = inner_buf.len();
let len = buf.len();
let src = inner_buf.as_ptr();
let dst = buf.as_mut_ptr().add(len);
core::ptr::copy_nonoverlapping(src, dst, count);
buf.set_len(len + count);
}
}
_ => {
buf.extend_from_slice(inner_buf);
}
}

let nread = inner_buf.len();
self.discard_buffer();
Ok(nread + self.inner.read_to_end(buf)?)
Expand Down Expand Up @@ -443,7 +477,31 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
let mut bytes = Vec::new();
self.read_to_end(&mut bytes)?;
let string = crate::str::from_utf8(&bytes).map_err(|_| io::Error::INVALID_UTF8)?;
*buf += string;

cfg_select! {
no_global_oom_handling => {
// SAFETY:
// * string and buf are non-overlapping
// * buf[..len] is already initialized
// * buf[len..len + count] is initialized by copy_nonoverlapping
// * len + count is within the capacity of buf based on the reservation completed above
// * buf is appended with valid UTF-8 data and is initially valid UTF-8, therefore
// it is valid UTF-8 at all times.
unsafe {
let buf = buf.as_mut_vec();
let count = string.len();
let len = buf.len();
let src = string.as_ptr();
let dst = buf.as_mut_ptr().add(len);
core::ptr::copy_nonoverlapping(src, dst, count);
buf.set_len(len + count);
}
}
_ => {
*buf += string;
}
}

Ok(string.len())
}
}
Expand Down Expand Up @@ -580,6 +638,8 @@ impl<R: ?Sized + Seek> Seek for BufReader<R> {
}
}

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl<T: ?Sized> SizeHint for BufReader<T> {
#[inline]
fn lower_bound(&self) -> usize {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

#[expect(missing_debug_implementations)]
pub struct Buffer {
// The buffer.
buf: Box<[MaybeUninit<u8>]>,
Expand All @@ -29,12 +32,15 @@ pub struct Buffer {
}

impl Buffer {
#[cfg(not(no_global_oom_handling))]
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let buf = Box::new_uninit_slice(capacity);
Self { buf, pos: 0, filled: 0, initialized: false }
}

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
#[inline]
pub fn try_with_capacity(capacity: usize) -> io::Result<Self> {
match Box::try_new_uninit_slice(capacity) {
Expand Down Expand Up @@ -68,7 +74,8 @@ impl Buffer {
}

// This is only used by a test which asserts that the initialization-tracking is correct.
#[cfg(test)]
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub fn initialized(&self) -> bool {
self.initialized
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
///
Expand Down Expand Up @@ -60,8 +62,8 @@ use crate::{error, fmt, ptr};
/// together by the buffer and will all be written out in one system call when
/// the `stream` is flushed.
///
/// [`TcpStream::write`]: crate::net::TcpStream::write
/// [`TcpStream`]: crate::net::TcpStream
/// [`TcpStream::write`]: ../../std/net/struct.TcpStream.html#method.write
/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
/// [`flush`]: BufWriter::flush
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufWriter<W: ?Sized + Write> {
Expand All @@ -87,20 +89,26 @@ impl<W: Write> BufWriter<W> {
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// # #[expect(unused_mut)]
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(inner: W) -> BufWriter<W> {
BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
}

pub(crate) fn try_new_buffer() -> io::Result<Vec<u8>> {
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub fn try_new_buffer() -> io::Result<Vec<u8>> {
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<u8>) -> Self {
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub fn with_buffer(inner: W, buf: Vec<u8>) -> Self {
Self { inner, buf, panicked: false }
}

Expand All @@ -115,8 +123,10 @@ impl<W: Write> BufWriter<W> {
/// use std::net::TcpStream;
///
/// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
/// # #[expect(unused_mut)]
/// let mut buffer = BufWriter::with_capacity(100, stream);
/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> {
BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false }
Expand All @@ -136,6 +146,7 @@ impl<W: Write> BufWriter<W> {
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// # #[expect(unused_mut)]
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // unwrap the TcpStream and flush the buffer
Expand Down Expand Up @@ -192,7 +203,9 @@ impl<W: ?Sized + Write> BufWriter<W> {
/// "successfully written" (by returning nonzero success values from
/// `write`), any 0-length writes from `inner` must be reported as i/o
/// errors from this method.
pub(in crate::io) fn flush_buf(&mut self) -> io::Result<()> {
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub fn flush_buf(&mut self) -> io::Result<()> {
// SAFETY: `<BufWriter as BufferedWriterSpec>::copy_from` assumes that
// this will not de-initialize any elements of `self.buf`'s spare
// capacity.
Expand Down Expand Up @@ -287,6 +300,7 @@ impl<W: ?Sized + Write> BufWriter<W> {
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// # #[expect(unused_mut)]
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // we can use reference just like buffer
Expand Down Expand Up @@ -343,7 +357,9 @@ impl<W: ?Sized + Write> BufWriter<W> {
/// That the buffer is a `Vec` is an implementation detail.
/// Callers should not modify the capacity as there currently is no public API to do so
/// and thus any capacity changes would be unexpected by the user.
pub(in crate::io) fn buffer_mut(&mut self) -> &mut Vec<u8> {
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub fn buffer_mut(&mut self) -> &mut Vec<u8> {
&mut self.buf
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl<W: Write> LineWriter<W> {
/// Ok(())
/// }
/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(inner: W) -> LineWriter<W> {
// Lines typically aren't that long, don't use a giant buffer
Expand All @@ -105,6 +106,7 @@ impl<W: Write> LineWriter<W> {
/// Ok(())
/// }
/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> {
LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<W>,
}

impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
pub(super) fn new(buffer: &'a mut BufWriter<W>) -> Self {
Self { buffer }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@ mod bufwriter;
mod linewriter;
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;

pub use self::bufwriter::WriterPanicked;
use self::linewritershim::LineWriterShim;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter};
use crate::io::Error;
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
Expand All @@ -27,6 +24,7 @@ use crate::{error, fmt};
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// # #[expect(unused_mut)]
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // do stuff with the stream
Expand Down Expand Up @@ -69,6 +67,7 @@ impl<W> IntoInnerError<W> {
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// # #[expect(unused_mut)]
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // do stuff with the stream
Expand Down Expand Up @@ -103,6 +102,7 @@ impl<W> IntoInnerError<W> {
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// # #[expect(unused_mut)]
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // do stuff with the stream
Expand Down
Loading