Coverage Report

Created: 2026-06-01 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.52.3/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
    /// 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
0
    pub fn stdout() -> Stdout {
132
0
        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
0
        let blocking = unsafe { Blocking::new(std) };
137
0
        Stdout {
138
0
            std: SplitByUtf8BoundaryIfWindows::new(blocking),
139
0
        }
140
0
    }
141
}
142
143
#[cfg(unix)]
144
mod sys {
145
    use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
146
147
    use super::Stdout;
148
149
    impl AsRawFd for Stdout {
150
0
        fn as_raw_fd(&self) -> RawFd {
151
0
            std::io::stdout().as_raw_fd()
152
0
        }
153
    }
154
155
    impl AsFd for Stdout {
156
0
        fn as_fd(&self) -> BorrowedFd<'_> {
157
0
            unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
158
0
        }
159
    }
160
}
161
162
cfg_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
178
impl AsyncWrite for Stdout {
179
0
    fn poll_write(
180
0
        mut self: Pin<&mut Self>,
181
0
        cx: &mut Context<'_>,
182
0
        buf: &[u8],
183
0
    ) -> Poll<io::Result<usize>> {
184
0
        Pin::new(&mut self.std).poll_write(cx, buf)
185
0
    }
186
187
0
    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
188
0
        Pin::new(&mut self.std).poll_flush(cx)
189
0
    }
190
191
0
    fn poll_shutdown(
192
0
        mut self: Pin<&mut Self>,
193
0
        cx: &mut Context<'_>,
194
0
    ) -> Poll<Result<(), io::Error>> {
195
0
        Pin::new(&mut self.std).poll_shutdown(cx)
196
0
    }
197
}