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