Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide optional Read/Write methods for stdio #136769

Merged
merged 4 commits into from
Mar 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
63 changes: 35 additions & 28 deletions library/std/src/io/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,39 +97,53 @@ 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]
fn is_read_vectored(&self) -> bool {
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]
Expand All @@ -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]
Expand All @@ -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,
}
}
Expand Down
12 changes: 6 additions & 6 deletions library/std/src/sys/stdio/sgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use fortanix_sgx_abi as abi;
use crate::io;
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);
Expand All @@ -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
}
}

Expand All @@ -28,7 +28,7 @@ impl io::Read for Stdin {

impl Stdout {
pub const fn new() -> Stdout {
Stdout(())
Stdout
}
}

Expand All @@ -44,7 +44,7 @@ impl io::Write for Stdout {

impl Stderr {
pub const fn new() -> Stderr {
Stderr(())
Stderr
}
}

Expand Down
59 changes: 8 additions & 51 deletions library/std/src/sys/stdio/solid.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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())
}
53 changes: 13 additions & 40 deletions library/std/src/sys/stdio/teeos.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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
Expand All @@ -54,31 +37,21 @@ 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<()> {
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 {
err.raw_os_error() == Some(libc::EBADF as i32)
Expand Down
12 changes: 6 additions & 6 deletions library/std/src/sys/stdio/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,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
}
}

Expand All @@ -45,7 +45,7 @@ impl io::Read for Stdin {

impl Stdout {
pub const fn new() -> Stdout {
Stdout(())
Stdout
}
}

Expand All @@ -71,7 +71,7 @@ impl io::Write for Stdout {

impl Stderr {
pub const fn new() -> Stderr {
Stderr(())
Stderr
}
}

Expand Down
Loading
Loading