From 5de65af8f04a53a3d4ca261224892c3d8cd1a107 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 12 May 2026 13:24:27 +1000 Subject: [PATCH] Move `std::io::read_to_string` to `alloc::io` --- library/alloc/src/io/mod.rs | 7 ++-- library/alloc/src/io/read.rs | 65 ++++++++++++++++++++++++++++++++++ library/std/src/io/mod.rs | 67 ++---------------------------------- 3 files changed, 72 insertions(+), 67 deletions(-) diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs index 748ac33c6d582..a3fc76634d55b 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -27,8 +27,6 @@ pub use core::io::{ stream_len_default, take, }; -#[unstable(feature = "alloc_io", issue = "154046")] -pub use self::{read::Read, util::Bytes}; #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub use self::{ @@ -38,3 +36,8 @@ pub use self::{ }, util::{SpecReadByte, bytes, uninlined_slow_read_byte}, }; +#[unstable(feature = "alloc_io", issue = "154046")] +pub use self::{ + read::{Read, read_to_string}, + util::Bytes, +}; diff --git a/library/alloc/src/io/read.rs b/library/alloc/src/io/read.rs index 8b020166203ba..c6b802ef9862a 100644 --- a/library/alloc/src/io/read.rs +++ b/library/alloc/src/io/read.rs @@ -700,6 +700,71 @@ pub trait Read { } } +/// 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) +} + /// Bare metal platforms usually have very small amounts of RAM /// (in the order of hundreds of KB) #[doc(hidden)] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index a20503f9d9205..d5de33a899e83 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -306,6 +306,8 @@ pub use alloc_crate::io::RawOsError; pub use alloc_crate::io::SimpleMessage; #[unstable(feature = "io_const_error", issue = "133448")] pub use alloc_crate::io::const_error; +#[stable(feature = "io_read_to_string", since = "1.65.0")] +pub use alloc_crate::io::read_to_string; #[unstable(feature = "read_buf", issue = "78485")] pub use alloc_crate::io::{BorrowedBuf, BorrowedCursor}; #[stable(feature = "rust1", since = "1.0.0")] @@ -359,71 +361,6 @@ mod util; pub(crate) use stdio::cleanup; -/// 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) -} - fn read_until(r: &mut R, delim: u8, buf: &mut Vec) -> Result { let mut read = 0; loop {