tokio/io/
stdin.rs

1use crate::io::blocking::Blocking;
2use crate::io::{AsyncRead, ReadBuf};
3
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 input stream of a process.
11    ///
12    /// The handle implements the [`AsyncRead`] trait, but beware that concurrent
13    /// reads of `Stdin` must be executed with care.
14    ///
15    /// This handle is best used for non-interactive uses, such as when a file
16    /// is piped into the application. For technical reasons, `stdin` is
17    /// implemented by using an ordinary blocking read on a separate thread, and
18    /// it is impossible to cancel that read. This can make shutdown of the
19    /// runtime hang until the user presses enter.
20    ///
21    /// For interactive uses, it is recommended to spawn a thread dedicated to
22    /// user input and use blocking IO directly in that thread.
23    ///
24    /// Created by the [`stdin`] function.
25    ///
26    /// [`stdin`]: fn@stdin
27    /// [`AsyncRead`]: trait@AsyncRead
28    #[derive(Debug)]
29    pub struct Stdin {
30        std: Blocking<std::io::Stdin>,
31    }
32
33    /// Constructs a new handle to the standard input of the current process.
34    ///
35    /// This handle is best used for non-interactive uses, such as when a file
36    /// is piped into the application. For technical reasons, `stdin` is
37    /// implemented by using an ordinary blocking read on a separate thread, and
38    /// it is impossible to cancel that read. This can make shutdown of the
39    /// runtime hang until the user presses enter.
40    ///
41    /// For interactive uses, it is recommended to spawn a thread dedicated to
42    /// user input and use blocking IO directly in that thread.
43    pub fn stdin() -> Stdin {
44        let std = io::stdin();
45        // SAFETY: The `Read` implementation of `std` does not read from the
46        // buffer it is borrowing and correctly reports the length of the data
47        // written into the buffer.
48        let std = unsafe { Blocking::new(std) };
49        Stdin {
50            std,
51        }
52    }
53}
54
55#[cfg(unix)]
56mod sys {
57    use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
58
59    use super::Stdin;
60
61    impl AsRawFd for Stdin {
62        fn as_raw_fd(&self) -> RawFd {
63            std::io::stdin().as_raw_fd()
64        }
65    }
66
67    impl AsFd for Stdin {
68        fn as_fd(&self) -> BorrowedFd<'_> {
69            unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
70        }
71    }
72}
73
74cfg_windows! {
75    use crate::os::windows::io::{AsHandle, BorrowedHandle, AsRawHandle, RawHandle};
76
77    impl AsRawHandle for Stdin {
78        fn as_raw_handle(&self) -> RawHandle {
79            std::io::stdin().as_raw_handle()
80        }
81    }
82
83    impl AsHandle for Stdin {
84        fn as_handle(&self) -> BorrowedHandle<'_> {
85            unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
86        }
87    }
88}
89
90impl AsyncRead for Stdin {
91    fn poll_read(
92        mut self: Pin<&mut Self>,
93        cx: &mut Context<'_>,
94        buf: &mut ReadBuf<'_>,
95    ) -> Poll<io::Result<()>> {
96        Pin::new(&mut self.std).poll_read(cx, buf)
97    }
98}