tokio/io/stderr.rs
1use crate::io::blocking::Blocking;
2use crate::io::stdio_common::SplitByUtf8BoundaryIfWindows;
3use crate::io::AsyncWrite;
4
5use std::io;
6use std::pin::Pin;
7use std::task::Context;
8use std::task::Poll;
9
10cfg_io_std! {
11 /// A handle to the standard error stream of a process.
12 ///
13 /// Concurrent writes to stderr must be executed with care: Only individual
14 /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular
15 /// you should be aware that writes using [`write_all`] are not guaranteed
16 /// to occur as a single write, so multiple threads writing data with
17 /// [`write_all`] may result in interleaved output.
18 ///
19 /// Created by the [`stderr`] function.
20 ///
21 /// [`stderr`]: stderr()
22 /// [`AsyncWrite`]: AsyncWrite
23 /// [`write_all`]: crate::io::AsyncWriteExt::write_all()
24 ///
25 /// # Examples
26 ///
27 /// ```
28 /// use tokio::io::{self, AsyncWriteExt};
29 ///
30 /// #[tokio::main]
31 /// async fn main() -> io::Result<()> {
32 /// let mut stderr = io::stderr();
33 /// stderr.write_all(b"Print some error here.").await?;
34 /// Ok(())
35 /// }
36 /// ```
37 #[derive(Debug)]
38 pub struct Stderr {
39 std: SplitByUtf8BoundaryIfWindows<Blocking<std::io::Stderr>>,
40 }
41
42 /// Constructs a new handle to the standard error of the current process.
43 ///
44 /// The returned handle allows writing to standard error from the within the
45 /// Tokio runtime.
46 ///
47 /// Concurrent writes to stderr must be executed with care: Only individual
48 /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular
49 /// you should be aware that writes using [`write_all`] are not guaranteed
50 /// to occur as a single write, so multiple threads writing data with
51 /// [`write_all`] may result in interleaved output.
52 ///
53 /// Note that unlike [`std::io::stderr`], each call to this `stderr()`
54 /// produces a new writer, so for example, this program does **not** flush stderr:
55 ///
56 /// ```no_run
57 /// # use tokio::io::AsyncWriteExt;
58 /// # #[tokio::main]
59 /// # async fn main() -> std::io::Result<()> {
60 /// tokio::io::stderr().write_all(b"aa").await?;
61 /// tokio::io::stderr().flush().await?;
62 /// # Ok(())
63 /// # }
64 /// ```
65 ///
66 /// [`std::io::stderr`]: std::io::stderr
67 /// [`AsyncWrite`]: AsyncWrite
68 /// [`write_all`]: crate::io::AsyncWriteExt::write_all()
69 ///
70 /// # Examples
71 ///
72 /// ```
73 /// use tokio::io::{self, AsyncWriteExt};
74 ///
75 /// #[tokio::main]
76 /// async fn main() -> io::Result<()> {
77 /// let mut stderr = io::stderr();
78 /// stderr.write_all(b"Print some error here.").await?;
79 /// Ok(())
80 /// }
81 /// ```
82 pub fn stderr() -> Stderr {
83 let std = io::stderr();
84 // SAFETY: The `Read` implementation of `std` does not read from the
85 // buffer it is borrowing and correctly reports the length of the data
86 // written into the buffer.
87 let blocking = unsafe { Blocking::new(std) };
88 Stderr {
89 std: SplitByUtf8BoundaryIfWindows::new(blocking),
90 }
91 }
92}
93
94#[cfg(unix)]
95mod sys {
96 use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
97
98 use super::Stderr;
99
100 impl AsRawFd for Stderr {
101 fn as_raw_fd(&self) -> RawFd {
102 std::io::stderr().as_raw_fd()
103 }
104 }
105
106 impl AsFd for Stderr {
107 fn as_fd(&self) -> BorrowedFd<'_> {
108 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
109 }
110 }
111}
112
113cfg_windows! {
114 use crate::os::windows::io::{AsHandle, BorrowedHandle, AsRawHandle, RawHandle};
115
116 impl AsRawHandle for Stderr {
117 fn as_raw_handle(&self) -> RawHandle {
118 std::io::stderr().as_raw_handle()
119 }
120 }
121
122 impl AsHandle for Stderr {
123 fn as_handle(&self) -> BorrowedHandle<'_> {
124 unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
125 }
126 }
127}
128
129impl AsyncWrite for Stderr {
130 fn poll_write(
131 mut self: Pin<&mut Self>,
132 cx: &mut Context<'_>,
133 buf: &[u8],
134 ) -> Poll<io::Result<usize>> {
135 Pin::new(&mut self.std).poll_write(cx, buf)
136 }
137
138 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
139 Pin::new(&mut self.std).poll_flush(cx)
140 }
141
142 fn poll_shutdown(
143 mut self: Pin<&mut Self>,
144 cx: &mut Context<'_>,
145 ) -> Poll<Result<(), io::Error>> {
146 Pin::new(&mut self.std).poll_shutdown(cx)
147 }
148}