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    /// 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    /// Note that unlike [`std::io::stdout`], each call to this `stdout()`
78    /// produces a new writer, so for example, this program does **not** flush stdout:
79    ///
80    /// ```no_run
81    /// # use tokio::io::AsyncWriteExt;
82    /// # #[tokio::main]
83    /// # async fn main() -> std::io::Result<()> {
84    /// tokio::io::stdout().write_all(b"aa").await?;
85    /// tokio::io::stdout().flush().await?;
86    /// # Ok(())
87    /// # }
88    /// ```
89    ///
90    /// [`std::io::stdout`]: std::io::stdout
91    /// [`AsyncWrite`]: AsyncWrite
92    /// [`write_all`]: crate::io::AsyncWriteExt::write_all()
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use tokio::io::{self, AsyncWriteExt};
98    ///
99    /// #[tokio::main]
100    /// async fn main() -> io::Result<()> {
101    ///     let mut stdout = io::stdout();
102    ///     stdout.write_all(b"Hello world!").await?;
103    ///     Ok(())
104    /// }
105    /// ```
106    ///
107    /// The following is an example of using `stdio` with loop.
108    ///
109    /// ```
110    /// use tokio::io::{self, AsyncWriteExt};
111    ///
112    /// #[tokio::main]
113    /// async fn main() {
114    ///     let messages = vec!["hello", " world\n"];
115    ///
116    ///     // When you use `stdio` in a loop, it is recommended to create
117    ///     // a single `stdio` instance outside the loop and call a write
118    ///     // operation against that instance on each loop.
119    ///     //
120    ///     // Repeatedly creating `stdout` instances inside the loop and
121    ///     // writing to that handle could result in mangled output since
122    ///     // each write operation is handled by a different blocking thread.
123    ///     let mut stdout = io::stdout();
124    ///
125    ///     for message in &messages {
126    ///         stdout.write_all(message.as_bytes()).await.unwrap();
127    ///         stdout.flush().await.unwrap();
128    ///     }
129    /// }
130    /// ```
131    pub fn stdout() -> Stdout {
132        let std = io::stdout();
133        // SAFETY: The `Read` implementation of `std` does not read from the
134        // buffer it is borrowing and correctly reports the length of the data
135        // written into the buffer.
136        let blocking = unsafe { Blocking::new(std) };
137        Stdout {
138            std: SplitByUtf8BoundaryIfWindows::new(blocking),
139        }
140    }
141}
142
143#[cfg(unix)]
144mod sys {
145    use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
146
147    use super::Stdout;
148
149    impl AsRawFd for Stdout {
150        fn as_raw_fd(&self) -> RawFd {
151            std::io::stdout().as_raw_fd()
152        }
153    }
154
155    impl AsFd for Stdout {
156        fn as_fd(&self) -> BorrowedFd<'_> {
157            unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
158        }
159    }
160}
161
162cfg_windows! {
163    use crate::os::windows::io::{AsHandle, BorrowedHandle, AsRawHandle, RawHandle};
164
165    impl AsRawHandle for Stdout {
166        fn as_raw_handle(&self) -> RawHandle {
167            std::io::stdout().as_raw_handle()
168        }
169    }
170
171    impl AsHandle for Stdout {
172        fn as_handle(&self) -> BorrowedHandle<'_> {
173            unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
174        }
175    }
176}
177
178impl AsyncWrite for Stdout {
179    fn poll_write(
180        mut self: Pin<&mut Self>,
181        cx: &mut Context<'_>,
182        buf: &[u8],
183    ) -> Poll<io::Result<usize>> {
184        Pin::new(&mut self.std).poll_write(cx, buf)
185    }
186
187    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
188        Pin::new(&mut self.std).poll_flush(cx)
189    }
190
191    fn poll_shutdown(
192        mut self: Pin<&mut Self>,
193        cx: &mut Context<'_>,
194    ) -> Poll<Result<(), io::Error>> {
195        Pin::new(&mut self.std).poll_shutdown(cx)
196    }
197}