terminal_io/
terminal_reader.rs1use crate::config::{detect_read_config, ReadConfig};
4use crate::{ReadTerminal, Terminal};
5use io_extras::grip::AsGrip;
6#[cfg(windows)]
7use io_extras::os::windows::{
8 AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, RawHandleOrSocket,
9};
10use std::io::{self, IoSliceMut, Read};
11#[cfg(not(windows))]
12use {
13 io_extras::os::rustix::{AsRawFd, RawFd},
14 std::os::fd::{AsFd, BorrowedFd},
15};
16
17#[derive(Debug)]
19pub struct TerminalReader<Inner: Read> {
20 inner: Inner,
21 read_config: Option<ReadConfig>,
22}
23
24impl<Inner: Read + AsGrip> TerminalReader<Inner> {
25 #[inline]
28 pub fn with_handle(inner: Inner) -> Self {
29 let read_config = detect_read_config(&inner);
30 Self { inner, read_config }
31 }
32}
33
34impl<Inner: Read> TerminalReader<Inner> {
35 #[inline]
38 pub fn generic(inner: Inner) -> Self {
39 Self {
40 inner,
41 read_config: None,
42 }
43 }
44
45 #[inline]
47 pub fn into_inner(self) -> Inner {
48 self.inner
49 }
50}
51
52#[cfg(not(windows))]
53impl<Inner: Read + AsRawFd> AsRawFd for TerminalReader<Inner> {
54 #[inline]
55 fn as_raw_fd(&self) -> RawFd {
56 self.inner.as_raw_fd()
57 }
58}
59
60#[cfg(not(windows))]
61impl<Inner: Read + AsFd> AsFd for TerminalReader<Inner> {
62 #[inline]
63 fn as_fd(&self) -> BorrowedFd<'_> {
64 self.inner.as_fd()
65 }
66}
67
68#[cfg(windows)]
69impl<Inner: Read + AsRawHandleOrSocket> AsRawHandleOrSocket for TerminalReader<Inner> {
70 #[inline]
71 fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
72 self.inner.as_raw_handle_or_socket()
73 }
74}
75
76#[cfg(windows)]
77impl<Inner: Read + AsHandleOrSocket> AsHandleOrSocket for TerminalReader<Inner> {
78 #[inline]
79 fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
80 self.inner.as_handle_or_socket()
81 }
82}
83
84impl<Inner: Read> Terminal for TerminalReader<Inner> {}
85
86impl<Inner: Read> ReadTerminal for TerminalReader<Inner> {
87 #[inline]
88 fn is_line_by_line(&self) -> bool {
89 self.read_config.as_ref().map_or(false, |c| c.line_by_line)
90 }
91
92 #[inline]
93 fn is_input_terminal(&self) -> bool {
94 self.read_config.is_some()
95 }
96}
97
98impl<Inner: Read> Read for TerminalReader<Inner> {
99 #[inline]
100 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
101 self.inner.read(buf)
102 }
103
104 #[inline]
105 fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
106 self.inner.read_vectored(bufs)
107 }
108
109 #[cfg(can_vector)]
110 #[inline]
111 fn is_read_vectored(&self) -> bool {
112 self.inner.is_read_vectored()
113 }
114
115 #[inline]
116 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
117 self.inner.read_to_end(buf)
118 }
119
120 #[inline]
121 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
122 self.inner.read_to_string(buf)
123 }
124
125 #[inline]
126 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
127 self.inner.read_exact(buf)
128 }
129}