semihosting/io/
stdio.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3use core::fmt;
4
5use crate::{fd::AsFd as _, io, sys};
6
7/// Constructs a new handle to the standard input of the current process.
8///
9/// Unlike [`std::io::stdin`], this function returns the `Result`.
10///
11/// # Platform-specific behavior
12///
13/// Currently, this function will always success on MIPS32/MIPS64, On other architectures,
14/// this may fail if semihosting is only partially supported.
15///
16/// Also, we have found that reading from stdin does not work well on MIPS32/MIPS64.
17///
18/// [`std::io::stdin`]: https://doc.rust-lang.org/std/io/fn.stdin.html
19pub fn stdin() -> io::Result<Stdin> {
20    sys::stdin().map(Stdin)
21}
22/// Constructs a new handle to the standard output of the current process.
23///
24/// Unlike [`std::io::stdout`], this function returns the `Result`.
25///
26/// # Platform-specific behavior
27///
28/// Currently, this function will always success on MIPS32/MIPS64, On other architectures,
29/// this may fail if semihosting is only partially supported.
30///
31/// [`std::io::stdout`]: https://doc.rust-lang.org/std/io/fn.stdout.html
32pub fn stdout() -> io::Result<Stdout> {
33    sys::stdout().map(Stdout)
34}
35/// Constructs a new handle to the standard error of the current process.
36///
37/// Unlike [`std::io::stderr`], this function returns the `Result`.
38///
39/// # Platform-specific behavior
40///
41/// Currently, this function will always success on MIPS32/MIPS64, On other architectures,
42/// this may fail if semihosting is only partially supported.
43///
44/// [`std::io::stderr`]: https://doc.rust-lang.org/std/io/fn.stderr.html
45pub fn stderr() -> io::Result<Stderr> {
46    sys::stderr().map(Stderr)
47}
48
49/// A handle to the standard input stream of a process.
50///
51/// Created by the [`io::stdin`] method.
52pub struct Stdin(sys::StdioFd);
53/// A handle to the standard output stream of a process.
54///
55/// Created by the [`io::stdout`] method.
56pub struct Stdout(sys::StdioFd);
57/// A handle to the standard error stream of a process.
58///
59/// Created by the [`io::stderr`] method.
60pub struct Stderr(sys::StdioFd);
61
62impl_as_fd!(Stdin, Stdout, Stderr);
63// TODO: std provides io trait implementations on &Std{in,out,err} as they uses locks.
64impl io::Read for Stdin {
65    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
66        sys::read(self.as_fd(), buf)
67    }
68}
69impl io::Write for Stdout {
70    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
71        sys::write(self.as_fd(), bytes)
72    }
73    fn flush(&mut self) -> io::Result<()> {
74        Ok(())
75    }
76}
77impl io::Write for Stderr {
78    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
79        sys::write(self.as_fd(), bytes)
80    }
81    fn flush(&mut self) -> io::Result<()> {
82        Ok(())
83    }
84}
85impl fmt::Debug for Stdin {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        f.debug_struct("Stdin").finish_non_exhaustive()
88    }
89}
90impl fmt::Debug for Stdout {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        f.debug_struct("Stdout").finish_non_exhaustive()
93    }
94}
95impl fmt::Debug for Stderr {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        f.debug_struct("Stderr").finish_non_exhaustive()
98    }
99}
100
101/// Trait to determine if a descriptor/handle refers to a terminal/tty.
102pub trait IsTerminal: crate::sealed::Sealed {
103    /// Returns `true` if the descriptor/handle refers to a terminal/tty.
104    ///
105    /// On platforms where Rust does not know how to detect a terminal yet, this will return
106    /// `false`. This will also return `false` if an unexpected error occurred, such as from
107    /// passing an invalid file descriptor.
108    #[doc(alias = "isatty")]
109    fn is_terminal(&self) -> bool;
110}
111macro_rules! impl_is_terminal {
112    ($($t:ty),*$(,)?) => {$(
113        impl crate::sealed::Sealed for $t {}
114        impl crate::io::IsTerminal for $t {
115            #[inline]
116            fn is_terminal(&self) -> bool {
117                use crate::fd::AsFd as _;
118                crate::sys::is_terminal(self.as_fd())
119            }
120        }
121    )*}
122}
123impl_is_terminal!(Stdin, Stdout, Stderr);
124#[cfg(feature = "fs")]
125impl_is_terminal!(crate::fs::File);