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 Stdout {
120 std: SplitByUtf8BoundaryIfWindows::new(Blocking::new(std)),
121 }
122 }
123}
124
125#[cfg(unix)]
126mod sys {
127 use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
128
129 use super::Stdout;
130
131 impl AsRawFd for Stdout {
132 fn as_raw_fd(&self) -> RawFd {
133 std::io::stdout().as_raw_fd()
134 }
135 }
136
137 impl AsFd for Stdout {
138 fn as_fd(&self) -> BorrowedFd<'_> {
139 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
140 }
141 }
142}
143
144cfg_windows! {
145 use crate::os::windows::io::{AsHandle, BorrowedHandle, AsRawHandle, RawHandle};
146
147 impl AsRawHandle for Stdout {
148 fn as_raw_handle(&self) -> RawHandle {
149 std::io::stdout().as_raw_handle()
150 }
151 }
152
153 impl AsHandle for Stdout {
154 fn as_handle(&self) -> BorrowedHandle<'_> {
155 unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
156 }
157 }
158}
159
160impl AsyncWrite for Stdout {
161 fn poll_write(
162 mut self: Pin<&mut Self>,
163 cx: &mut Context<'_>,
164 buf: &[u8],
165 ) -> Poll<io::Result<usize>> {
166 Pin::new(&mut self.std).poll_write(cx, buf)
167 }
168
169 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
170 Pin::new(&mut self.std).poll_flush(cx)
171 }
172
173 fn poll_shutdown(
174 mut self: Pin<&mut Self>,
175 cx: &mut Context<'_>,
176 ) -> Poll<Result<(), io::Error>> {
177 Pin::new(&mut self.std).poll_shutdown(cx)
178 }
179}