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}