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}