Coverage Report

Created: 2026-09-01 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.53.1/src/io/stdout.rs
Line
Count
Source
1
use crate::io::blocking::Blocking;
2
use crate::io::stdio_common::SplitByUtf8BoundaryIfWindows;
3
use crate::io::AsyncWrite;
4
use std::io;
5
use std::pin::Pin;
6
use std::task::Context;
7
use std::task::Poll;
8
9
cfg_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
0
    pub fn stdout() -> Stdout {
171
0
        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
0
        let blocking = unsafe { Blocking::new(std) };
176
0
        Stdout {
177
0
            std: SplitByUtf8BoundaryIfWindows::new(blocking),
178
0
        }
179
0
    }
180
}
181
182
#[cfg(unix)]
183
mod sys {
184
    use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
185
186
    use super::Stdout;
187
188
    impl AsRawFd for Stdout {
189
0
        fn as_raw_fd(&self) -> RawFd {
190
0
            std::io::stdout().as_raw_fd()
191
0
        }
192
    }
193
194
    impl AsFd for Stdout {
195
0
        fn as_fd(&self) -> BorrowedFd<'_> {
196
0
            unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
197
0
        }
198
    }
199
}
200
201
cfg_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
217
impl AsyncWrite for Stdout {
218
0
    fn poll_write(
219
0
        mut self: Pin<&mut Self>,
220
0
        cx: &mut Context<'_>,
221
0
        buf: &[u8],
222
0
    ) -> Poll<io::Result<usize>> {
223
0
        Pin::new(&mut self.std).poll_write(cx, buf)
224
0
    }
225
226
0
    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
227
0
        Pin::new(&mut self.std).poll_flush(cx)
228
0
    }
229
230
0
    fn poll_shutdown(
231
0
        mut self: Pin<&mut Self>,
232
0
        cx: &mut Context<'_>,
233
0
    ) -> Poll<Result<(), io::Error>> {
234
0
        Pin::new(&mut self.std).poll_shutdown(cx)
235
0
    }
236
}