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}