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}