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     /// [`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)]
126 mod sys {
127     use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
128 
129     use super::Stdout;
130 
131     impl AsRawFd for Stdout {
as_raw_fd(&self) -> RawFd132         fn as_raw_fd(&self) -> RawFd {
133             std::io::stdout().as_raw_fd()
134         }
135     }
136 
137     impl AsFd for Stdout {
as_fd(&self) -> BorrowedFd<'_>138         fn as_fd(&self) -> BorrowedFd<'_> {
139             unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
140         }
141     }
142 }
143 
144 cfg_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 
160 impl AsyncWrite for Stdout {
poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>>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 
poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>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 
poll_shutdown( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll<Result<(), io::Error>>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 }
180