about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-03-23 06:23:51 +0000
committerbors <bors@rust-lang.org>2025-03-23 06:23:51 +0000
commit60a3084f64607e86dd7715d72f11764cd500c364 (patch)
treeb6abe6c3d8f0e42e6cea362f761a29f080c23789 /library/std/src
parentf08d5c01e69436891ff1c181385d0e078a8482ec (diff)
parentf6e90d804a82cce1606596f6116402843794deb3 (diff)
downloadrust-60a3084f64607e86dd7715d72f11764cd500c364.tar.gz
rust-60a3084f64607e86dd7715d72f11764cd500c364.zip
Auto merge of #136769 - thaliaarchi:io-optional-methods/stdio, r=joboet
Provide optional `Read`/`Write` methods for stdio

Override more of the default methods for `io::Read` and `io::Write` for stdio types, when efficient to do so, and deduplicate unsupported types.

Tracked in https://github.com/rust-lang/rust/issues/136756.

try-job: x86_64-msvc-1
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/io/stdio.rs63
-rw-r--r--library/std/src/sys/stdio/sgx.rs12
-rw-r--r--library/std/src/sys/stdio/solid.rs59
-rw-r--r--library/std/src/sys/stdio/teeos.rs53
-rw-r--r--library/std/src/sys/stdio/unix.rs12
-rw-r--r--library/std/src/sys/stdio/unsupported.rs71
-rw-r--r--library/std/src/sys/stdio/xous.rs27
7 files changed, 136 insertions, 161 deletions
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index ce46241f8e8..8fc16331339 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -97,15 +97,15 @@ const fn stderr_raw() -> StderrRaw {
 
 impl Read for StdinRaw {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        handle_ebadf(self.0.read(buf), 0)
+        handle_ebadf(self.0.read(buf), || Ok(0))
     }
 
     fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
-        handle_ebadf(self.0.read_buf(buf), ())
+        handle_ebadf(self.0.read_buf(buf), || Ok(()))
     }
 
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        handle_ebadf(self.0.read_vectored(bufs), 0)
+        handle_ebadf(self.0.read_vectored(bufs), || Ok(0))
     }
 
     #[inline]
@@ -113,23 +113,37 @@ impl Read for StdinRaw {
         self.0.is_read_vectored()
     }
 
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        if buf.is_empty() {
+            return Ok(());
+        }
+        handle_ebadf(self.0.read_exact(buf), || Err(io::Error::READ_EXACT_EOF))
+    }
+
+    fn read_buf_exact(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        if buf.capacity() == 0 {
+            return Ok(());
+        }
+        handle_ebadf(self.0.read_buf_exact(buf), || Err(io::Error::READ_EXACT_EOF))
+    }
+
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        handle_ebadf(self.0.read_to_end(buf), 0)
+        handle_ebadf(self.0.read_to_end(buf), || Ok(0))
     }
 
     fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
-        handle_ebadf(self.0.read_to_string(buf), 0)
+        handle_ebadf(self.0.read_to_string(buf), || Ok(0))
     }
 }
 
 impl Write for StdoutRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        handle_ebadf(self.0.write(buf), buf.len())
+        handle_ebadf(self.0.write(buf), || Ok(buf.len()))
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let total = || bufs.iter().map(|b| b.len()).sum();
-        handle_ebadf_lazy(self.0.write_vectored(bufs), total)
+        let total = || Ok(bufs.iter().map(|b| b.len()).sum());
+        handle_ebadf(self.0.write_vectored(bufs), total)
     }
 
     #[inline]
@@ -138,30 +152,30 @@ impl Write for StdoutRaw {
     }
 
     fn flush(&mut self) -> io::Result<()> {
-        handle_ebadf(self.0.flush(), ())
+        handle_ebadf(self.0.flush(), || Ok(()))
     }
 
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        handle_ebadf(self.0.write_all(buf), ())
+        handle_ebadf(self.0.write_all(buf), || Ok(()))
     }
 
     fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
-        handle_ebadf(self.0.write_all_vectored(bufs), ())
+        handle_ebadf(self.0.write_all_vectored(bufs), || Ok(()))
     }
 
     fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
-        handle_ebadf(self.0.write_fmt(fmt), ())
+        handle_ebadf(self.0.write_fmt(fmt), || Ok(()))
     }
 }
 
 impl Write for StderrRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        handle_ebadf(self.0.write(buf), buf.len())
+        handle_ebadf(self.0.write(buf), || Ok(buf.len()))
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let total = || bufs.iter().map(|b| b.len()).sum();
-        handle_ebadf_lazy(self.0.write_vectored(bufs), total)
+        let total = || Ok(bufs.iter().map(|b| b.len()).sum());
+        handle_ebadf(self.0.write_vectored(bufs), total)
     }
 
     #[inline]
@@ -170,32 +184,25 @@ impl Write for StderrRaw {
     }
 
     fn flush(&mut self) -> io::Result<()> {
-        handle_ebadf(self.0.flush(), ())
+        handle_ebadf(self.0.flush(), || Ok(()))
     }
 
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        handle_ebadf(self.0.write_all(buf), ())
+        handle_ebadf(self.0.write_all(buf), || Ok(()))
     }
 
     fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
-        handle_ebadf(self.0.write_all_vectored(bufs), ())
+        handle_ebadf(self.0.write_all_vectored(bufs), || Ok(()))
     }
 
     fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
-        handle_ebadf(self.0.write_fmt(fmt), ())
-    }
-}
-
-fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
-    match r {
-        Err(ref e) if stdio::is_ebadf(e) => Ok(default),
-        r => r,
+        handle_ebadf(self.0.write_fmt(fmt), || Ok(()))
     }
 }
 
-fn handle_ebadf_lazy<T>(r: io::Result<T>, default: impl FnOnce() -> T) -> io::Result<T> {
+fn handle_ebadf<T>(r: io::Result<T>, default: impl FnOnce() -> io::Result<T>) -> io::Result<T> {
     match r {
-        Err(ref e) if stdio::is_ebadf(e) => Ok(default()),
+        Err(ref e) if stdio::is_ebadf(e) => default(),
         r => r,
     }
 }
diff --git a/library/std/src/sys/stdio/sgx.rs b/library/std/src/sys/stdio/sgx.rs
index 1894c098d18..2cf47f49192 100644
--- a/library/std/src/sys/stdio/sgx.rs
+++ b/library/std/src/sys/stdio/sgx.rs
@@ -3,9 +3,9 @@ use fortanix_sgx_abi as abi;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::sys::fd::FileDesc;
 
-pub struct Stdin(());
-pub struct Stdout(());
-pub struct Stderr(());
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
 
 fn with_std_fd<F: FnOnce(&FileDesc) -> R, R>(fd: abi::Fd, f: F) -> R {
     let fd = FileDesc::new(fd);
@@ -16,7 +16,7 @@ fn with_std_fd<F: FnOnce(&FileDesc) -> R, R>(fd: abi::Fd, f: F) -> R {
 
 impl Stdin {
     pub const fn new() -> Stdin {
-        Stdin(())
+        Stdin
     }
 }
 
@@ -41,7 +41,7 @@ impl io::Read for Stdin {
 
 impl Stdout {
     pub const fn new() -> Stdout {
-        Stdout(())
+        Stdout
     }
 }
 
@@ -66,7 +66,7 @@ impl io::Write for Stdout {
 
 impl Stderr {
     pub const fn new() -> Stderr {
-        Stderr(())
+        Stderr
     }
 }
 
diff --git a/library/std/src/sys/stdio/solid.rs b/library/std/src/sys/stdio/solid.rs
index a2ff4bb212f..55daf0b54b9 100644
--- a/library/std/src/sys/stdio/solid.rs
+++ b/library/std/src/sys/stdio/solid.rs
@@ -1,22 +1,13 @@
+#[expect(dead_code)]
+#[path = "unsupported.rs"]
+mod unsupported_stdio;
+
 use crate::io;
 use crate::sys::pal::abi;
 
-pub struct Stdin;
+pub type Stdin = unsupported_stdio::Stdin;
 pub struct Stdout;
-pub struct Stderr;
-struct PanicOutput;
-
-impl Stdin {
-    pub const fn new() -> Stdin {
-        Stdin
-    }
-}
-
-impl io::Read for Stdin {
-    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
-        Ok(0)
-    }
-}
+pub type Stderr = Stdout;
 
 impl Stdout {
     pub const fn new() -> Stdout {
@@ -35,46 +26,12 @@ impl io::Write for Stdout {
     }
 }
 
-impl Stderr {
-    pub const fn new() -> Stderr {
-        Stderr
-    }
-}
-
-impl io::Write for Stderr {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) };
-        Ok(buf.len())
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-impl PanicOutput {
-    pub const fn new() -> PanicOutput {
-        PanicOutput
-    }
-}
-
-impl io::Write for PanicOutput {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) };
-        Ok(buf.len())
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-pub const STDIN_BUF_SIZE: usize = 0;
+pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE;
 
 pub fn is_ebadf(_err: &io::Error) -> bool {
     true
 }
 
 pub fn panic_output() -> Option<impl io::Write> {
-    Some(PanicOutput::new())
+    Some(Stderr::new())
 }
diff --git a/library/std/src/sys/stdio/teeos.rs b/library/std/src/sys/stdio/teeos.rs
index 67e251812da..27b3292bf8f 100644
--- a/library/std/src/sys/stdio/teeos.rs
+++ b/library/std/src/sys/stdio/teeos.rs
@@ -1,12 +1,16 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
+#[expect(dead_code)]
+#[path = "unsupported.rs"]
+mod unsupported_stdio;
+
 use core::arch::asm;
 
 use crate::io;
 
-pub struct Stdin;
+pub type Stdin = unsupported_stdio::Stdin;
 pub struct Stdout;
-pub struct Stderr;
+pub type Stderr = Stdout;
 
 const KCALL_DEBUG_CMD_PUT_BYTES: i64 = 2;
 
@@ -25,27 +29,6 @@ unsafe fn debug_call(cap_ref: u64, call_no: i64, arg1: u64, arg2: u64) -> i32 {
     ret as i32
 }
 
-fn print_buf(s: &[u8]) -> io::Result<usize> {
-    // Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`.
-    const MAX_LEN: usize = 512;
-    let len = if s.len() > MAX_LEN { MAX_LEN } else { s.len() };
-    let result = unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, s.as_ptr() as u64, len as u64) };
-
-    if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) }
-}
-
-impl Stdin {
-    pub const fn new() -> Stdin {
-        Stdin
-    }
-}
-
-impl io::Read for Stdin {
-    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
-        Ok(0)
-    }
-}
-
 impl Stdout {
     pub const fn new() -> Stdout {
         Stdout
@@ -54,23 +37,13 @@ impl Stdout {
 
 impl io::Write for Stdout {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        print_buf(buf)
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
+        // Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`.
+        const MAX_LEN: usize = 512;
+        let len = buf.len().min(MAX_LEN);
+        let result =
+            unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, buf.as_ptr() as u64, len as u64) };
 
-impl Stderr {
-    pub const fn new() -> Stderr {
-        Stderr
-    }
-}
-
-impl io::Write for Stderr {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        print_buf(buf)
+        if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) }
     }
 
     fn flush(&mut self) -> io::Result<()> {
@@ -78,7 +51,7 @@ impl io::Write for Stderr {
     }
 }
 
-pub const STDIN_BUF_SIZE: usize = 0;
+pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE;
 
 pub fn is_ebadf(err: &io::Error) -> bool {
     err.raw_os_error() == Some(libc::EBADF as i32)
diff --git a/library/std/src/sys/stdio/unix.rs b/library/std/src/sys/stdio/unix.rs
index 08a06e0da9f..8535e3539e9 100644
--- a/library/std/src/sys/stdio/unix.rs
+++ b/library/std/src/sys/stdio/unix.rs
@@ -11,13 +11,13 @@ use crate::os::hermit::io::FromRawFd;
 use crate::os::unix::io::FromRawFd;
 use crate::sys::fd::FileDesc;
 
-pub struct Stdin(());
-pub struct Stdout(());
-pub struct Stderr(());
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
 
 impl Stdin {
     pub const fn new() -> Stdin {
-        Stdin(())
+        Stdin
     }
 }
 
@@ -42,7 +42,7 @@ impl io::Read for Stdin {
 
 impl Stdout {
     pub const fn new() -> Stdout {
-        Stdout(())
+        Stdout
     }
 }
 
@@ -68,7 +68,7 @@ impl io::Write for Stdout {
 
 impl Stderr {
     pub const fn new() -> Stderr {
-        Stderr(())
+        Stderr
     }
 }
 
diff --git a/library/std/src/sys/stdio/unsupported.rs b/library/std/src/sys/stdio/unsupported.rs
index b5e3f5be988..177264f5c10 100644
--- a/library/std/src/sys/stdio/unsupported.rs
+++ b/library/std/src/sys/stdio/unsupported.rs
@@ -1,8 +1,8 @@
-use crate::io;
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 
 pub struct Stdin;
 pub struct Stdout;
-pub struct Stderr;
+pub type Stderr = Stdout;
 
 impl Stdin {
     pub const fn new() -> Stdin {
@@ -11,9 +11,47 @@ impl Stdin {
 }
 
 impl io::Read for Stdin {
+    #[inline]
     fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
         Ok(0)
     }
+
+    #[inline]
+    fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        Ok(())
+    }
+
+    #[inline]
+    fn read_vectored(&mut self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        Ok(0)
+    }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        // Do not force `Chain<Empty, T>` or `Chain<T, Empty>` to use vectored
+        // reads, unless the other reader is vectored.
+        false
+    }
+
+    #[inline]
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
+    }
+
+    #[inline]
+    fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        if cursor.capacity() != 0 { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
+    }
+
+    #[inline]
+    fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
+        Ok(0)
+    }
+
+    #[inline]
+    fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
+        Ok(0)
+    }
 }
 
 impl Stdout {
@@ -23,26 +61,35 @@ impl Stdout {
 }
 
 impl io::Write for Stdout {
+    #[inline]
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         Ok(buf.len())
     }
 
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
+    #[inline]
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let total_len = bufs.iter().map(|b| b.len()).sum();
+        Ok(total_len)
     }
-}
 
-impl Stderr {
-    pub const fn new() -> Stderr {
-        Stderr
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
     }
-}
 
-impl io::Write for Stderr {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        Ok(buf.len())
+    #[inline]
+    fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
+        Ok(())
     }
 
+    #[inline]
+    fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        Ok(())
+    }
+
+    // Keep the default write_fmt so the `fmt::Arguments` are still evaluated.
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
diff --git a/library/std/src/sys/stdio/xous.rs b/library/std/src/sys/stdio/xous.rs
index 71736145221..a92167642b7 100644
--- a/library/std/src/sys/stdio/xous.rs
+++ b/library/std/src/sys/stdio/xous.rs
@@ -1,27 +1,18 @@
-use crate::io;
-
-pub struct Stdin;
-pub struct Stdout {}
-pub struct Stderr;
+#[expect(dead_code)]
+#[path = "unsupported.rs"]
+mod unsupported_stdio;
 
+use crate::io;
 use crate::os::xous::ffi::{Connection, lend, try_lend, try_scalar};
 use crate::os::xous::services::{LogLend, LogScalar, log_server, try_connect};
 
-impl Stdin {
-    pub const fn new() -> Stdin {
-        Stdin
-    }
-}
-
-impl io::Read for Stdin {
-    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
-        Ok(0)
-    }
-}
+pub type Stdin = unsupported_stdio::Stdin;
+pub struct Stdout;
+pub struct Stderr;
 
 impl Stdout {
     pub const fn new() -> Stdout {
-        Stdout {}
+        Stdout
     }
 }
 
@@ -73,7 +64,7 @@ impl io::Write for Stderr {
     }
 }
 
-pub const STDIN_BUF_SIZE: usize = 0;
+pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE;
 
 pub fn is_ebadf(_err: &io::Error) -> bool {
     true