From c4d12cba88de290cc5ef6b64ef0c12ab4995e640 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Fri, 22 May 2026 08:38:41 +1000 Subject: [PATCH 1/9] Setup `core::io::prelude` --- library/core/src/io/mod.rs | 2 ++ library/core/src/io/prelude.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 library/core/src/io/prelude.rs diff --git a/library/core/src/io/mod.rs b/library/core/src/io/mod.rs index 0134540ae86c8..a44d271535a9e 100644 --- a/library/core/src/io/mod.rs +++ b/library/core/src/io/mod.rs @@ -5,6 +5,8 @@ mod cursor; mod error; mod impls; mod io_slice; +#[unstable(feature = "core_io", issue = "154046")] +pub mod prelude; mod seek; mod size_hint; mod util; diff --git a/library/core/src/io/prelude.rs b/library/core/src/io/prelude.rs new file mode 100644 index 0000000000000..15dacaa3a4fa0 --- /dev/null +++ b/library/core/src/io/prelude.rs @@ -0,0 +1,12 @@ +//! The I/O Prelude. +//! +//! The purpose of this module is to alleviate imports of many common I/O traits +//! by adding a glob import to the top of I/O heavy modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! use std::io::prelude::*; +//! ``` + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::io::{Seek, Write}; From 0791c08ecbef1e98f72fcf42792e6017d8a4684b Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Fri, 22 May 2026 08:38:58 +1000 Subject: [PATCH 2/9] Setup `alloc::io::prelude` --- library/alloc/src/io/mod.rs | 2 ++ library/alloc/src/io/prelude.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 library/alloc/src/io/prelude.rs diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs index 5c043240daba8..be2d17bb5a9e6 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -6,6 +6,8 @@ mod copy; mod cursor; mod error; mod impls; +#[unstable(feature = "alloc_io", issue = "154046")] +pub mod prelude; mod read; mod util; diff --git a/library/alloc/src/io/prelude.rs b/library/alloc/src/io/prelude.rs new file mode 100644 index 0000000000000..86ae040d1d6f6 --- /dev/null +++ b/library/alloc/src/io/prelude.rs @@ -0,0 +1,12 @@ +//! The I/O Prelude. +//! +//! The purpose of this module is to alleviate imports of many common I/O traits +//! by adding a glob import to the top of I/O heavy modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! use std::io::prelude::*; +//! ``` + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::io::{BufRead, Read, Seek, Write}; From d95198739c2623c9e0b4f26d26c54ccd70d8e0a9 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Sun, 19 Jul 2026 21:13:23 +1000 Subject: [PATCH 3/9] Expand documentation for `alloc::io` --- library/alloc/src/io/mod.rs | 175 ++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs index be2d17bb5a9e6..44d780292317f 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -1,4 +1,179 @@ //! Traits, helpers, and type definitions for core I/O functionality. +//! +//! The `io` module contains a number of common things you'll need +//! when doing input and output. The most core part of this module is +//! the [`Read`] and [`Write`] traits, which provide the +//! most general interface for reading and writing input and output. +//! +//! ## Read and Write +//! +//! Because they are traits, [`Read`] and [`Write`] are implemented by a number +//! of other types, and you can implement them for your types too. As such, +//! you'll see a few different types of I/O throughout the documentation in +//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! [`File`]s: +//! +//! ```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(()) +//! } +//! ``` +//! +//! [`Read`] and [`Write`] are so important, implementors of the two traits have a +//! nickname: readers and writers. So you'll sometimes see 'a reader' instead +//! of 'a type that implements the [`Read`] trait'. Much easier! +//! +//! ## Seek and BufRead +//! +//! Beyond that, there are two important traits that are provided: [`Seek`] +//! and [`BufRead`]. Both of these build on top of a reader to control +//! how the reading happens. [`Seek`] lets you control where the next byte is +//! coming from: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::SeekFrom; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; +//! +//! // skip to the last 10 bytes of the file +//! f.seek(SeekFrom::End(-10))?; +//! +//! // read up to 10 bytes +//! let n = f.read(&mut buffer)?; +//! +//! println!("The bytes: {:?}", &buffer[..n]); +//! Ok(()) +//! } +//! ``` +//! +//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but +//! to show it off, we'll need to talk about buffers in general. Keep reading! +//! +//! ## BufReader and BufWriter +//! +//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be +//! making near-constant calls to the operating system. To help with this, +//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap +//! readers and writers. The wrapper uses a buffer, reducing the number of +//! calls and providing nicer methods for accessing exactly what you want. +//! +//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra +//! methods to any reader: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); +//! +//! // read a line into buffer +//! reader.read_line(&mut buffer)?; +//! +//! println!("{buffer}"); +//! Ok(()) +//! } +//! ``` +//! +//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call +//! to [`write`][`Write::write`]: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufWriter; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::create("foo.txt")?; +//! { +//! let mut writer = BufWriter::new(f); +//! +//! // write a byte to the buffer +//! writer.write(&[42])?; +//! +//! } // the buffer is flushed once writer goes out of scope +//! +//! Ok(()) +//! } +//! ``` +//! +//! ## Iterator types +//! +//! A large number of the structures provided by `std::io` are for various +//! ways of iterating over I/O. For example, [`Lines`] is used to split over +//! lines: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let reader = BufReader::new(f); +//! +//! for line in reader.lines() { +//! println!("{}", line?); +//! } +//! Ok(()) +//! } +//! ``` +//! +//! ## io::Result +//! +//! Last, but certainly not least, is [`io::Result`]. This type is used +//! as the return type of many `std::io` functions that can cause an error, and +//! can be returned from your own functions as well. Many of the examples in this +//! module use the [`?` operator]: +//! +//! ```no_run +//! use std::io; +//! +//! # #[allow(dead_code)] +//! fn read_input() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! io::stdin().read_line(&mut input)?; +//! +//! println!("You typed: {}", input.trim()); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very +//! common type for functions which don't have a 'real' return value, but do want to +//! return errors if they happen. In this case, the only purpose of this function is +//! to read the line and print it, so we use `()`. +//! +//! [`File`]: ../../std/fs/struct.File.html +//! [`TcpStream`]: ../../std/net/struct.TcpStream.html +//! [`Vec`]: crate::vec::Vec +//! [`io::Result`]: self::Result +//! [`?` operator]: ../../book/appendix-02-operators.html mod buf_read; mod buffered; From 32117cda49c21aecbe8d0430f766b53211e73094 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 21 May 2026 11:18:11 +1000 Subject: [PATCH 4/9] Move general IO tests to `alloctests` --- .../io/tests.rs => alloctests/tests/io/mod.rs} | 16 ++++++++++------ library/alloctests/tests/lib.rs | 12 ++++++++++++ library/std/src/io/mod.rs | 3 --- 3 files changed, 22 insertions(+), 9 deletions(-) rename library/{std/src/io/tests.rs => alloctests/tests/io/mod.rs} (98%) diff --git a/library/std/src/io/tests.rs b/library/alloctests/tests/io/mod.rs similarity index 98% rename from library/std/src/io/tests.rs rename to library/alloctests/tests/io/mod.rs index 3b4f871268cd1..fcc27dbbd73f7 100644 --- a/library/std/src/io/tests.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,7 +1,11 @@ -use super::{BorrowedBuf, Cursor, SeekFrom, repeat}; -use crate::cmp::{self, min}; -use crate::io::{self, BufRead, BufReader, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, Write}; -use crate::mem::MaybeUninit; +use alloc::io::{ + self, BorrowedBuf, BufRead, BufReader, Cursor, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, SeekFrom, + Write, repeat, +}; +use core::cmp::{self, min}; +use core::mem::MaybeUninit; + +extern crate test; #[test] fn read_until() { @@ -270,7 +274,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(); @@ -360,7 +364,7 @@ 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) + alloc::io::default_read_to_end(&mut lr, &mut vec, None) }); } diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 7ccc8d9c6a115..e787e3af9b636 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -2,23 +2,30 @@ #![allow(internal_features)] #![deny(implicit_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +#![feature(alloc_io)] #![feature(allocator_api)] #![feature(binary_heap_drain_sorted)] #![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_pop_if)] +#![feature(borrowed_buf_init)] +#![feature(buf_read_has_data_left)] #![feature(casefold)] #![feature(const_btree_len)] #![feature(const_cmp)] #![feature(const_heap)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] +#![feature(core_io_borrowed_buf)] +#![feature(core_io_internals)] #![feature(cow_is_borrowed)] +#![feature(cursor_split)] #![feature(deque_extend_front)] #![feature(downcast_unchecked)] #![feature(drain_keep_rest)] #![feature(exact_size_is_empty)] #![feature(hashmap_internals)] #![feature(inplace_iteration)] +#![feature(io_const_error)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_next_chunk)] @@ -28,6 +35,9 @@ #![feature(map_try_insert)] #![feature(pattern)] #![feature(ptr_cast_slice)] +#![feature(read_buf)] +#![feature(seek_io_take_position)] +#![feature(seek_stream_len)] #![feature(slice_partial_sort_unstable)] #![feature(slice_partition_dedup)] #![feature(slice_ptr_get)] @@ -48,6 +58,7 @@ #![feature(vec_deque_retain_range)] #![feature(vec_peek_mut)] #![feature(vec_try_remove)] +#![feature(write_all_vectored)] // tidy-alphabetical-end extern crate alloc; @@ -67,6 +78,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/io/mod.rs b/library/std/src/io/mod.rs index 203572c9067b6..d9cbe15c1d4f6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -294,9 +294,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(test)] -mod tests; - use alloc_crate::io::OsFunctions; #[unstable(feature = "raw_os_error_ty", issue = "107792")] pub use alloc_crate::io::RawOsError; From 125be4beff372ce676908a5e7de60c6bcac7daa7 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 21 May 2026 11:31:20 +1000 Subject: [PATCH 5/9] Move `std::io::util` tests to `alloctests` --- library/alloctests/tests/io/mod.rs | 2 ++ .../io/util/tests.rs => alloctests/tests/io/util.rs} | 10 +++++----- library/alloctests/tests/lib.rs | 1 + library/std/src/io/mod.rs | 1 - library/std/src/io/util.rs | 2 -- 5 files changed, 8 insertions(+), 8 deletions(-) rename library/{std/src/io/util/tests.rs => alloctests/tests/io/util.rs} (96%) delete mode 100644 library/std/src/io/util.rs diff --git a/library/alloctests/tests/io/mod.rs b/library/alloctests/tests/io/mod.rs index fcc27dbbd73f7..77fd3723ff158 100644 --- a/library/alloctests/tests/io/mod.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,3 +1,5 @@ +mod util; + use alloc::io::{ self, BorrowedBuf, BufRead, BufReader, Cursor, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, SeekFrom, Write, repeat, diff --git a/library/std/src/io/util/tests.rs b/library/alloctests/tests/io/util.rs similarity index 96% rename from library/std/src/io/util/tests.rs rename to library/alloctests/tests/io/util.rs index ed1d6891577da..52e0c3013dde7 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::{ - BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Repeat, SeekFrom, Sink, empty, repeat, sink, +use alloc::io::{ + BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Read, Repeat, Seek, SeekFrom, Sink, Write, + 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 e787e3af9b636..eb9ea287d950f 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -9,6 +9,7 @@ #![feature(binary_heap_pop_if)] #![feature(borrowed_buf_init)] #![feature(buf_read_has_data_left)] +#![feature(can_vector)] #![feature(casefold)] #![feature(const_btree_len)] #![feature(const_cmp)] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index d9cbe15c1d4f6..385b8081a33ff 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -349,4 +349,3 @@ mod impls; mod pipe; pub mod prelude; mod stdio; -mod util; diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/util.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; From 39bf757d697baad2fae42fc2df9d59bd8e1d7a55 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 21 May 2026 11:42:23 +1000 Subject: [PATCH 6/9] Move `std::io::cursor` tests to `alloctests` --- .../src/io/cursor/tests.rs => alloctests/tests/io/cursor.rs} | 5 +++-- library/alloctests/tests/io/mod.rs | 1 + library/std/src/io/cursor.rs | 2 -- library/std/src/io/mod.rs | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) rename library/{std/src/io/cursor/tests.rs => alloctests/tests/io/cursor.rs} (99%) delete mode 100644 library/std/src/io/cursor.rs diff --git a/library/std/src/io/cursor/tests.rs b/library/alloctests/tests/io/cursor.rs similarity index 99% rename from library/std/src/io/cursor/tests.rs rename to library/alloctests/tests/io/cursor.rs index d7c203c297fe6..5e863f29af53c 100644 --- a/library/std/src/io/cursor/tests.rs +++ b/library/alloctests/tests/io/cursor.rs @@ -1,5 +1,6 @@ -use crate::io::prelude::*; -use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; +use alloc::io::{Cursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; + +extern crate test; #[test] fn test_vec_writer() { diff --git a/library/alloctests/tests/io/mod.rs b/library/alloctests/tests/io/mod.rs index 77fd3723ff158..a3fbbf96653cb 100644 --- a/library/alloctests/tests/io/mod.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,3 +1,4 @@ +mod cursor; mod util; use alloc::io::{ diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/cursor.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 385b8081a33ff..9cb63ebe9cd72 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -343,7 +343,6 @@ pub use self::stdio::{set_output_capture, try_set_output_capture}; mod buffered; mod copy; -mod cursor; mod error; mod impls; mod pipe; From f67f57d68c00f11620ddaf7736d86e199a341583 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 21 May 2026 11:45:18 +1000 Subject: [PATCH 7/9] Move `std::io::buffered` tests to `alloctests` --- .../tests/io/buffered.rs} | 31 ++++++++++--------- library/alloctests/tests/io/mod.rs | 1 + library/std/src/io/buffered/mod.rs | 4 --- library/std/src/io/mod.rs | 1 - 4 files changed, 18 insertions(+), 19 deletions(-) rename library/{std/src/io/buffered/tests.rs => alloctests/tests/io/buffered.rs} (98%) delete mode 100644 library/std/src/io/buffered/mod.rs diff --git a/library/std/src/io/buffered/tests.rs b/library/alloctests/tests/io/buffered.rs similarity index 98% rename from library/std/src/io/buffered/tests.rs rename to library/alloctests/tests/io/buffered.rs index ff4585a60cae9..0abaa63870e15 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/alloctests/tests/io/buffered.rs @@ -1,10 +1,14 @@ -use crate::io::prelude::*; -use crate::io::{ - self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom, +//! Tests for buffering wrappers for I/O traits + +use alloc::io::{ + self, BorrowedBuf, BufRead, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, Read, Seek, + SeekFrom, Write, }; -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}; + +extern crate test; /// A dummy reader intended at testing short-reads propagation. pub struct ShortReader { @@ -488,7 +492,7 @@ fn dont_panic_in_drop_on_panicked_flush() { } #[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn panic_in_write_doesnt_flush_in_drop() { static WRITES: AtomicUsize = AtomicUsize::new(0); @@ -504,12 +508,11 @@ fn panic_in_write_doesnt_flush_in_drop() { } } - thread::spawn(|| { + panic::catch_unwind(panic::AssertUnwindSafe(|| { let mut writer = BufWriter::new(PanicWriter); let _ = writer.write(b"hello world"); let _ = writer.flush(); - }) - .join() + })) .unwrap_err(); assert_eq!(WRITES.load(Ordering::SeqCst), 1); @@ -681,7 +684,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 }, @@ -1150,7 +1153,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()) @@ -1183,7 +1186,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]) -> alloc::io::Result { if buf.len() > 0 { buf[0] = 0; Ok(1) @@ -1206,7 +1209,7 @@ 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}; + use alloc::io::{BufWriter, Cursor}; let mut v = vec![0; 1024]; let c = Cursor::new(&mut v); let w = BufWriter::new(Box::new(c)); diff --git a/library/alloctests/tests/io/mod.rs b/library/alloctests/tests/io/mod.rs index a3fbbf96653cb..b0df3b51094ca 100644 --- a/library/alloctests/tests/io/mod.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,3 +1,4 @@ +mod buffered; mod cursor; mod util; diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs deleted file mode 100644 index 1d09ff7d8dc1c..0000000000000 --- a/library/std/src/io/buffered/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Buffering wrappers for I/O traits - -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 9cb63ebe9cd72..945de19424f3b 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -341,7 +341,6 @@ pub(crate) use self::stdio::{attempt_print_to_stderr, cleanup}; #[doc(no_inline, hidden)] pub use self::stdio::{set_output_capture, try_set_output_capture}; -mod buffered; mod copy; mod error; mod impls; From 29da936fe337721cdb5c320e2229339cdaa6dd7f Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Mon, 25 May 2026 13:29:57 +1000 Subject: [PATCH 8/9] Move `std::io::impls` benchmarks to `alloctests` --- library/{std/src/io/impls/tests.rs => alloctests/benches/io.rs} | 2 +- library/alloctests/benches/lib.rs | 1 + library/std/src/io/impls.rs | 2 -- library/std/src/io/mod.rs | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) rename library/{std/src/io/impls/tests.rs => alloctests/benches/io.rs} (97%) delete mode 100644 library/std/src/io/impls.rs diff --git a/library/std/src/io/impls/tests.rs b/library/alloctests/benches/io.rs similarity index 97% rename from library/std/src/io/impls/tests.rs rename to library/alloctests/benches/io.rs index d1cd84a67ada5..5ee8263b8cea4 100644 --- a/library/std/src/io/impls/tests.rs +++ b/library/alloctests/benches/io.rs @@ -1,4 +1,4 @@ -use crate::io::prelude::*; +use std::io::prelude::*; #[bench] fn bench_read_slice(b: &mut test::Bencher) { diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs index 4b7139d943593..974b389a765d5 100644 --- a/library/alloctests/benches/lib.rs +++ b/library/alloctests/benches/lib.rs @@ -12,6 +12,7 @@ extern crate test; mod binary_heap; mod btree; +mod io; mod linked_list; mod slice; mod str; diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/impls.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 945de19424f3b..ebd69e93fa98f 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -343,7 +343,6 @@ pub use self::stdio::{set_output_capture, try_set_output_capture}; mod copy; mod error; -mod impls; mod pipe; pub mod prelude; mod stdio; From 5b49a9daf874ea1779139d9bf48bec98e9bc4b62 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Sun, 2 Aug 2026 07:08:45 +1000 Subject: [PATCH 9/9] Move `std::io::copy` tests to `alloctests` --- library/alloctests/benches/io.rs | 23 +++++++++++ .../tests.rs => alloctests/tests/io/copy.rs} | 40 +++---------------- library/alloctests/tests/io/mod.rs | 1 + library/std/src/io/copy.rs | 2 - library/std/src/io/mod.rs | 1 - 5 files changed, 29 insertions(+), 38 deletions(-) rename library/{std/src/io/copy/tests.rs => alloctests/tests/io/copy.rs} (74%) delete mode 100644 library/std/src/io/copy.rs diff --git a/library/alloctests/benches/io.rs b/library/alloctests/benches/io.rs index 5ee8263b8cea4..f2e3f2cd3c998 100644 --- a/library/alloctests/benches/io.rs +++ b/library/alloctests/benches/io.rs @@ -55,3 +55,26 @@ fn bench_write_vec(b: &mut test::Bencher) { } }) } + +#[bench] +#[cfg(unix)] +#[cfg_attr(target_os = "emscripten", ignore)] // no /dev +fn bench_copy_buf_reader(b: &mut test::Bencher) { + use std::fs::{File, OpenOptions}; + + 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 = std::io::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); + std::io::copy(&mut reader, &mut writer).unwrap() + }); +} diff --git a/library/std/src/io/copy/tests.rs b/library/alloctests/tests/io/copy.rs similarity index 74% rename from library/std/src/io/copy/tests.rs rename to library/alloctests/tests/io/copy.rs index 7bdba3a04416e..485deeaea80e7 100644 --- a/library/std/src/io/copy/tests.rs +++ b/library/alloctests/tests/io/copy.rs @@ -1,7 +1,6 @@ -use crate::cmp::{max, min}; -use crate::collections::VecDeque; -use crate::io; -use crate::io::*; +use alloc::collections::VecDeque; +use alloc::io::{self, *}; +use core::cmp::{max, min}; #[test] fn copy_copies() { @@ -65,7 +64,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!(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 +72,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!(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 +116,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/alloctests/tests/io/mod.rs b/library/alloctests/tests/io/mod.rs index b0df3b51094ca..712e322d79f1c 100644 --- a/library/alloctests/tests/io/mod.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,4 +1,5 @@ mod buffered; +mod copy; mod cursor; mod util; diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/copy.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index ebd69e93fa98f..c0ed06d5311bc 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -341,7 +341,6 @@ pub(crate) use self::stdio::{attempt_print_to_stderr, cleanup}; #[doc(no_inline, hidden)] pub use self::stdio::{set_output_capture, try_set_output_capture}; -mod copy; mod error; mod pipe; pub mod prelude;