tokio/io/
stdout.rs

1use crate::io::blocking::Blocking;
2use crate::io::stdio_common::SplitByUtf8BoundaryIfWindows;
3use crate::io::AsyncWrite;
4use std::io;
5use std::pin::Pin;
6use std::task::Context;
7use std::task::Poll;
8
9cfg_io_std! {
10    /// A handle to the standard output stream of a process.
11    ///
12    /// Concurrent writes to stdout must be executed with care: Only individual
13    /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular
14    /// you should be aware that writes using [`write_all`] are not guaranteed
15    /// to occur as a single write, so multiple threads writing data with
16    /// [`write_all`] may result in interleaved output.
17    ///
18    /// Created by the [`stdout`] function.
19    ///
20    /// [`stdout`]: stdout()
21    /// [`AsyncWrite`]: AsyncWrite
22    /// [`write_all`]: crate::io::AsyncWriteExt::write_all()
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use tokio::io::{self, AsyncWriteExt};
28    ///
29    /// #[tokio::main]
30    /// async fn main() -> io::Result<()> {
31    ///     let mut stdout = io::stdout();
32    ///     stdout.write_all(b"Hello world!").await?;
33    ///     Ok(())
34    /// }
35    /// ```
36    ///
37    /// The following is an example of using `stdio` with loop.
38    ///
39    /// ```
40    /// use tokio::io::{self, AsyncWriteExt};
41    ///
42    /// #[tokio::main]
43    /// async fn main() {
44    ///     let messages = vec!["hello", " world\n"];
45    ///
46    ///     // When you use `stdio` in a loop, it is recommended to create
47    ///     // a single `stdio` instance outside the loop and call a write
48    ///     // operation against that instance on each loop.
49    ///     //
50    ///     // Repeatedly creating `stdout` instances inside the loop and
51    ///     // writing to that handle could result in mangled output since
52    ///     // each write operation is handled by a different blocking thread.
53    ///     let mut stdout = io::stdout();
54    ///
55    ///     for message in &messages {
56    ///         stdout.write_all(message.as_bytes()).await.unwrap();
57    ///         stdout.flush().await.unwrap();
58    ///     }
59    /// }
60    /// ```
61    #[derive(Debug)]
62    pub struct Stdout {
63        std: SplitByUtf8BoundaryIfWindows<Blocking<std::io::Stdout>>,
64    }
65
66    /// Constructs a new handle to the standard output of the current process.
67    ///
68    /// The returned handle allows writing to standard out from the within the
69    /// Tokio runtime.
70    ///
71    /// Concurrent writes to stdout must be executed with care: Only individual
72    /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular
73    /// you should be aware that writes using [`write_all`] are not guaranteed
74    /// to occur as a single write, so multiple threads writing data with
75    /// [`write_all`] may result in interleaved output.
76    ///
77    /// [`AsyncWrite`]: AsyncWrite
78    /// [`write_all`]: crate::io::AsyncWriteExt::write_all()
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// use tokio::io::{self, AsyncWriteExt};
84    ///
85    /// #[tokio::main]
86    /// async fn main() -> io::Result<()> {
87    ///     let mut stdout = io::stdout();
88    ///     stdout.write_all(b"Hello world!").await?;
89    ///     Ok(())
90    /// }
91    /// ```
92    ///
93    /// The following is an example of using `stdio` with loop.
94    ///
95    /// ```
96    /// use tokio::io::{self, AsyncWriteExt};
97    ///
98    /// #[tokio::main]
99    /// async fn main() {
100    ///     let messages = vec!["hello", " world\n"];
101    ///
102    ///     // When you use `stdio` in a loop, it is recommended to create
103    ///     // a single `stdio` instance outside the loop and call a write
104    ///     // operation against that instance on each loop.
105    ///     //
106    ///     // Repeatedly creating `stdout` instances inside the loop and
107    ///     // writing to that handle could result in mangled output since
108    ///     // each write operation is handled by a different blocking thread.
109    ///     let mut stdout = io::stdout();
110    ///
111    ///     for message in &messages {
112    ///         stdout.write_all(message.as_bytes()).await.unwrap();
113    ///         stdout.flush().await.unwrap();
114    ///     }
115    /// }
116    /// ```
117    pub fn stdout() -> Stdout {
118        let std = io::stdout();
119        // SAFETY: The `Read` implementation of `std` does not read from the
120        // buffer it is borrowing and correctly reports the length of the data
121        // written into the buffer.
122        let blocking = unsafe { Blocking::new(std) };
123        Stdout {
124            std: SplitByUtf8BoundaryIfWindows::new(blocking),
125        }
126    }
127}
128
129#[cfg(unix)]
130mod sys {
131    use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
132
133    use super::Stdout;
134
135    impl AsRawFd for Stdout {
136        fn as_raw_fd(&self) -> RawFd {
137            std::io::stdout().as_raw_fd()
138        }
139    }
140
141    impl AsFd for Stdout {
142        fn as_fd(&self) -> BorrowedFd<'_> {
143            unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
144        }
145    }
146}
147
148cfg_windows! {
149    use crate::os::windows::io::{AsHandle, BorrowedHandle, AsRawHandle, RawHandle};
150
151    impl AsRawHandle for Stdout {
152        fn as_raw_handle(&self) -> RawHandle {
153            std::io::stdout().as_raw_handle()
154        }
155    }
156
157    impl AsHandle for Stdout {
158        fn as_handle(&self) -> BorrowedHandle<'_> {
159            unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
160        }
161    }
162}
163
164impl AsyncWrite for Stdout {
165    fn poll_write(
166        mut self: Pin<&mut Self>,
167        cx: &mut Context<'_>,
168        buf: &[u8],
169    ) -> Poll<io::Result<usize>> {
170        Pin::new(&mut self.std).poll_write(cx, buf)
171    }
172
173    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
174        Pin::new(&mut self.std).poll_flush(cx)
175    }
176
177    fn poll_shutdown(
178        mut self: Pin<&mut Self>,
179        cx: &mut Context<'_>,
180    ) -> Poll<Result<(), io::Error>> {
181        Pin::new(&mut self.std).poll_shutdown(cx)
182    }
183}