1use core::future::Future;
13use core::pin::Pin;
14use core::task::{Context, Poll, ready};
15use std::io;
16
17use futures_io::{AsyncRead, AsyncWrite};
18
19use crate::task::Join;
20
21const MAX_BUF: usize = 16 * 1024;
23
24type Done<T> = (io::Result<usize>, Vec<u8>, T);
26
27#[derive(Debug)]
29enum Blocking<T> {
30 Idle { inner: T, buf: Vec<u8>, pos: usize },
33 Busy(Join<Done<T>>),
35 Gone,
37}
38
39impl<T: Send + 'static> Blocking<T> {
40 fn new(inner: T) -> Self {
41 Self::Idle {
42 inner,
43 buf: Vec::new(),
44 pos: 0,
45 }
46 }
47
48 fn poll_idle(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
51 let Self::Busy(job) = self else {
52 return Poll::Ready(Ok(0));
53 };
54 let done = ready!(Pin::new(job).poll(cx));
55 match done {
56 Ok((result, buf, inner)) => {
57 *self = Self::Idle { inner, buf, pos: 0 };
58 Poll::Ready(result)
59 }
60 Err(err) => {
61 *self = Self::Gone;
62 Poll::Ready(Err(err.into()))
63 }
64 }
65 }
66
67 fn start(
68 &mut self,
69 op: impl FnOnce(&mut T, &mut Vec<u8>) -> io::Result<usize> + Send + 'static,
70 ) {
71 if let Self::Idle { inner, buf, .. } = core::mem::replace(self, Self::Gone) {
72 let (mut inner, mut buf) = (inner, buf);
73 *self = Self::Busy(
74 crate::runtime::spawn_blocking(move || {
75 let result = op(&mut inner, &mut buf);
76 (result, buf, inner)
77 })
78 .join(),
79 );
80 }
81 }
82
83 fn gone() -> io::Error {
84 io::Error::other("the standard stream was lost with its blocking task")
85 }
86}
87
88impl<T: io::Read + Send + 'static> Blocking<T> {
89 fn poll_read(&mut self, cx: &mut Context<'_>, out: &mut [u8]) -> Poll<io::Result<usize>> {
90 loop {
91 match self {
92 Self::Idle { buf, pos, .. } if *pos < buf.len() => {
93 let n = (buf.len() - *pos).min(out.len());
94 out[..n].copy_from_slice(&buf[*pos..*pos + n]);
95 *pos += n;
96 return Poll::Ready(Ok(n));
97 }
98 Self::Idle { .. } => {
99 if out.is_empty() {
100 return Poll::Ready(Ok(0));
101 }
102 let want = out.len().min(MAX_BUF);
103 self.start(move |inner, buf| {
104 buf.clear();
105 buf.resize(want, 0);
106 let n = inner.read(buf)?;
107 buf.truncate(n);
108 Ok(n)
109 });
110 }
111 Self::Busy(_) => {
112 let result = ready!(self.poll_idle(cx));
113 if let Err(err) = result {
114 return Poll::Ready(Err(err));
115 }
116 if let Self::Idle { buf, .. } = self
117 && buf.is_empty()
118 {
119 return Poll::Ready(Ok(0));
120 }
121 }
122 Self::Gone => return Poll::Ready(Err(Self::gone())),
123 }
124 }
125 }
126}
127
128impl<T: io::Write + Send + 'static> Blocking<T> {
129 fn poll_write(&mut self, cx: &mut Context<'_>, input: &[u8]) -> Poll<io::Result<usize>> {
130 ready!(self.poll_idle(cx))?;
131 if input.is_empty() {
134 return Poll::Ready(Ok(0));
135 }
136 match self {
137 Self::Idle { buf, .. } => {
138 let n = input.len().min(MAX_BUF);
139 buf.clear();
140 buf.extend_from_slice(&input[..n]);
141 self.start(|inner, buf| inner.write_all(buf).map(|()| buf.len()));
142 Poll::Ready(Ok(n))
143 }
144 Self::Busy(_) => Poll::Pending,
145 Self::Gone => Poll::Ready(Err(Self::gone())),
146 }
147 }
148
149 fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
150 loop {
151 match self {
152 Self::Busy(_) => {
153 ready!(self.poll_idle(cx))?;
154 if let Self::Idle { buf, .. } = self
155 && buf.is_empty()
156 {
157 return Poll::Ready(Ok(()));
159 }
160 self.start(|inner, buf| {
162 buf.clear();
163 inner.flush().map(|()| 0)
164 });
165 }
166 Self::Idle { .. } => {
167 self.start(|inner, buf| {
168 buf.clear();
169 inner.flush().map(|()| 0)
170 });
171 }
172 Self::Gone => return Poll::Ready(Err(Self::gone())),
173 }
174 }
175 }
176}
177
178macro_rules! std_stream {
179 ($(#[$doc:meta])* $name:ident, $make:ident, $std:ident, $what:literal) => {
180 $(#[$doc])*
181 #[derive(Debug)]
182 pub struct $name {
183 inner: Blocking<std::io::$std>,
184 }
185
186 #[doc = concat!("The process's ", $what, ", as an async stream (see [`", stringify!($name), "`]).")]
187 pub fn $make() -> $name {
188 $name {
189 inner: Blocking::new(std::io::$make()),
190 }
191 }
192 };
193}
194
195std_stream!(
196 Stdin, stdin, Stdin, "standard input"
198);
199std_stream!(
200 Stdout, stdout, Stdout, "standard output"
203);
204std_stream!(
205 Stderr, stderr, Stderr, "standard error"
208);
209
210impl AsyncRead for Stdin {
211 fn poll_read(
212 self: Pin<&mut Self>,
213 cx: &mut Context<'_>,
214 buf: &mut [u8],
215 ) -> Poll<io::Result<usize>> {
216 self.get_mut().inner.poll_read(cx, buf)
217 }
218}
219
220macro_rules! write_stream {
221 ($($name:ident),*) => {$(
222 impl AsyncWrite for $name {
223 fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
224 self.get_mut().inner.poll_write(cx, buf)
225 }
226
227 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
228 self.get_mut().inner.poll_flush(cx)
229 }
230
231 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
232 self.get_mut().inner.poll_flush(cx)
233 }
234 }
235 )*};
236}
237write_stream!(Stdout, Stderr);
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242 use crate::io::{AsyncReadExt, AsyncWriteExt};
243 use std::sync::{Arc, Mutex};
244
245 #[derive(Clone, Default)]
247 struct Recorder(Arc<Mutex<(Vec<u8>, usize)>>);
248
249 impl io::Write for Recorder {
250 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
251 self.0.lock().unwrap().0.extend_from_slice(buf);
252 Ok(buf.len())
253 }
254
255 fn flush(&mut self) -> io::Result<()> {
256 self.0.lock().unwrap().1 += 1;
257 Ok(())
258 }
259 }
260
261 struct Wrap<T>(Blocking<T>);
262
263 impl<T: io::Write + Send + Unpin + 'static> AsyncWrite for Wrap<T> {
264 fn poll_write(
265 self: Pin<&mut Self>,
266 cx: &mut Context<'_>,
267 buf: &[u8],
268 ) -> Poll<io::Result<usize>> {
269 self.get_mut().0.poll_write(cx, buf)
270 }
271 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
272 self.get_mut().0.poll_flush(cx)
273 }
274 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
275 self.get_mut().0.poll_flush(cx)
276 }
277 }
278
279 impl<T: io::Read + Send + Unpin + 'static> AsyncRead for Wrap<T> {
280 fn poll_read(
281 self: Pin<&mut Self>,
282 cx: &mut Context<'_>,
283 buf: &mut [u8],
284 ) -> Poll<io::Result<usize>> {
285 self.get_mut().0.poll_read(cx, buf)
286 }
287 }
288
289 #[test]
290 fn writes_reach_the_stream_in_order_and_a_flush_waits_for_them() {
291 crate::block_on(async {
292 let record = Recorder::default();
293 let mut w = Wrap(Blocking::new(record.clone()));
294 let big = vec![b'b'; MAX_BUF * 2 + 5];
295 w.write_all(b"").await.unwrap();
296 w.flush().await.unwrap();
297 assert_eq!(
298 record.0.lock().unwrap().1,
299 1,
300 "a flush after an empty write flushes"
301 );
302 w.write_all(b"head ").await.unwrap();
303 w.write_all(&big).await.unwrap();
304 w.write_all(b" tail").await.unwrap();
305 w.flush().await.unwrap();
306 let (bytes, flushes) = record.0.lock().unwrap().clone();
307 assert_eq!(bytes.len(), 5 + big.len() + 5);
308 assert!(bytes.starts_with(b"head ") && bytes.ends_with(b" tail"));
309 assert_eq!(flushes, 2);
310 });
311 }
312
313 #[test]
314 fn reads_hand_out_what_one_blocking_read_gave() {
315 crate::block_on(async {
316 let mut r = Wrap(Blocking::new(&b"abcdefghij"[..]));
317 let mut three = [0u8; 3];
318 r.read_exact(&mut three).await.unwrap();
319 assert_eq!(&three, b"abc");
320 let mut rest = Vec::new();
321 r.read_to_end(&mut rest).await.unwrap();
322 assert_eq!(rest, b"defghij");
323 });
324 }
325
326 struct Broken;
328
329 impl io::Write for Broken {
330 fn write(&mut self, _: &[u8]) -> io::Result<usize> {
331 Err(io::ErrorKind::BrokenPipe.into())
332 }
333 fn flush(&mut self) -> io::Result<()> {
334 Ok(())
335 }
336 }
337
338 #[test]
339 fn a_failed_write_is_reported_by_the_next_operation() {
340 crate::block_on(async {
341 let mut w = Wrap(Blocking::new(Broken));
342 assert_eq!(
343 w.write(b"x").await.unwrap(),
344 1,
345 "answered while the pool writes it"
346 );
347 let err = w.flush().await.unwrap_err();
348 assert_eq!(err.kind(), io::ErrorKind::BrokenPipe);
349 });
350 }
351
352 #[test]
353 fn the_process_streams_take_writes() {
354 crate::block_on(async {
355 let mut out = stdout();
356 out.write_all(b"").await.unwrap();
357 out.flush().await.unwrap();
358 let mut err = stderr();
359 err.flush().await.unwrap();
360 });
361 }
362}