Skip to main content

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    /// # Warning
19    ///
20    /// Each call to [`stdout()`] creates a **new** handle with its own
21    /// internal state. Writes through different handles are not
22    /// coordinated, so creating a new handle in a loop can cause output
23    /// to appear out of order:
24    ///
25    /// ```no_run
26    /// # use tokio::io::{self, AsyncWriteExt};
27    /// # #[tokio::main]
28    /// # async fn main() -> std::io::Result<()> {
29    /// // WRONG: creates a new handle each iteration
30    /// for i in 0..10 {
31    ///     let mut out = io::stdout();
32    ///     out.write_all(b"data").await?;
33    ///     out.write_all(b"\n").await?;
34    ///     // out is dropped here; its last write may still be
35    ///     // running when the next iteration starts
36    /// }
37    /// # Ok(())
38    /// # }
39    /// ```
40    ///
41    /// To preserve order, create one handle outside the loop and
42    /// reuse it:
43    ///
44    /// ```no_run
45    /// # use tokio::io::{self, AsyncWriteExt};
46    /// # #[tokio::main]
47    /// # async fn main() -> std::io::Result<()> {
48    /// let mut out = io::stdout();
49    /// for i in 0..10 {
50    ///     out.write_all(b"data").await?;
51    ///     out.write_all(b"\n").await?;
52    /// }
53    /// # Ok(())
54    /// # }
55    /// ```
56    ///
57    /// Created by the [`stdout`] function.
58    ///
59    /// [`stdout`]: stdout()
60    /// [`AsyncWrite`]: AsyncWrite
61    /// [`write_all`]: crate::io::AsyncWriteExt::write_all()
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// use tokio::io::{self, AsyncWriteExt};
67    ///
68    /// #[tokio::main]
69    /// async fn main() -> io::Result<()> {
70    ///     let mut stdout = io::stdout();
71    ///     stdout.write_all(b"Hello world!").await?;
72    ///     Ok(())
73    /// }
74    /// ```
75    ///
76    /// The following is an example of using `stdio` with loop.
77    ///
78    /// ```
79    /// use tokio::io::{self, AsyncWriteExt};
80    ///
81    /// #[tokio::main]
82    /// async fn main() {
83    ///     let messages = vec!["hello", " world\n"];
84    ///
85    ///     // When you use `stdio` in a loop, it is recommended to create
86    ///     // a single `stdio` instance outside the loop and call a write
87    ///     // operation against that instance on each loop.
88    ///     //
89    ///     // Repeatedly creating `stdout` instances inside the loop and
90    ///     // writing to that handle could result in mangled output since
91    ///     // each write operation is handled by a different blocking thread.
92    ///     let mut stdout = io::stdout();
93    ///
94    ///     for message in &messages {
95    ///         stdout.write_all(message.as_bytes()).await.unwrap();
96    ///         stdout.flush().await.unwrap();
97    ///     }
98    /// }
99    /// ```
100    #[derive(Debug)]
101    pub struct Stdout {
102        std: SplitByUtf8BoundaryIfWindows<Blocking<std::io::Stdout>>,
103    }
104
105    /// Constructs a new handle to the standard output of the current process.
106    ///
107    /// The returned handle allows writing to standard out from the within the
108    /// Tokio runtime.
109    ///
110    /// Concurrent writes to stdout must be executed with care: Only individual
111    /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular
112    /// you should be aware that writes using [`write_all`] are not guaranteed
113    /// to occur as a single write, so multiple threads writing data with
114    /// [`write_all`] may result in interleaved output.
115    ///
116    /// Note that unlike [`std::io::stdout`], each call to this `stdout()`
117    /// produces a new writer, so for example, this program does **not** flush stdout:
118    ///
119    /// ```no_run
120    /// # use tokio::io::AsyncWriteExt;
121    /// # #[tokio::main]
122    /// # async fn main() -> std::io::Result<()> {
123    /// tokio::io::stdout().write_all(b"aa").await?;
124    /// tokio::io::stdout().flush().await?;
125    /// # Ok(())
126    /// # }
127    /// ```
128    ///
129    /// [`std::io::stdout`]: std::io::stdout
130    /// [`AsyncWrite`]: AsyncWrite
131    /// [`write_all`]: crate::io::AsyncWriteExt::write_all()
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// use tokio::io::{self, AsyncWriteExt};
137    ///
138    /// #[tokio::main]
139    /// async fn main() -> io::Result<()> {
140    ///     let mut stdout = io::stdout();
141    ///     stdout.write_all(b"Hello world!").await?;
142    ///     Ok(())
143    /// }
144    /// ```
145    ///
146    /// The following is an example of using `stdio` with loop.
147    ///
148    /// ```
149    /// use tokio::io::{self, AsyncWriteExt};
150    ///
151    /// #[tokio::main]
152    /// async fn main() {
153    ///     let messages = vec!["hello", " world\n"];
154    ///
155    ///     // When you use `stdio` in a loop, it is recommended to create
156    ///     // a single `stdio` instance outside the loop and call a write
157    ///     // operation against that instance on each loop.
158    ///     //
159    ///     // Repeatedly creating `stdout` instances inside the loop and
160    ///     // writing to that handle could result in mangled output since
161    ///     // each write operation is handled by a different blocking thread.
162    ///     let mut stdout = io::stdout();
163    ///
164    ///     for message in &messages {
165    ///         stdout.write_all(message.as_bytes()).await.unwrap();
166    ///         stdout.flush().await.unwrap();
167    ///     }
168    /// }
169    /// ```
170    pub fn stdout() -> Stdout {
171        let std = io::stdout();
172        // SAFETY: The `Read` implementation of `std` does not read from the
173        // buffer it is borrowing and correctly reports the length of the data
174        // written into the buffer.
175        let blocking = unsafe { Blocking::new(std) };
176        Stdout {
177            std: SplitByUtf8BoundaryIfWindows::new(blocking),
178        }
179    }
180}
181
182#[cfg(unix)]
183mod sys {
184    use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
185
186    use super::Stdout;
187
188    impl AsRawFd for Stdout {
189        fn as_raw_fd(&self) -> RawFd {
190            std::io::stdout().as_raw_fd()
191        }
192    }
193
194    impl AsFd for Stdout {
195        fn as_fd(&self) -> BorrowedFd<'_> {
196            unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
197        }
198    }
199}
200
201cfg_windows! {
202    use crate::os::windows::io::{AsHandle, BorrowedHandle, AsRawHandle, RawHandle};
203
204    impl AsRawHandle for Stdout {
205        fn as_raw_handle(&self) -> RawHandle {
206            std::io::stdout().as_raw_handle()
207        }
208    }
209
210    impl AsHandle for Stdout {
211        fn as_handle(&self) -> BorrowedHandle<'_> {
212            unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
213        }
214    }
215}
216
217impl AsyncWrite for Stdout {
218    fn poll_write(
219        mut self: Pin<&mut Self>,
220        cx: &mut Context<'_>,
221        buf: &[u8],
222    ) -> Poll<io::Result<usize>> {
223        Pin::new(&mut self.std).poll_write(cx, buf)
224    }
225
226    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
227        Pin::new(&mut self.std).poll_flush(cx)
228    }
229
230    fn poll_shutdown(
231        mut self: Pin<&mut Self>,
232        cx: &mut Context<'_>,
233    ) -> Poll<Result<(), io::Error>> {
234        Pin::new(&mut self.std).poll_shutdown(cx)
235    }
236}