1use crate::utf8_input::Utf8Input;
2use crate::utf8_output::Utf8Output;
3use crate::{ReadStr, WriteStr};
4use duplex::{Duplex, HalfDuplex};
5#[cfg(windows)]
6use io_extras::os::windows::{
7 AsHandleOrSocket, AsRawHandleOrSocket, AsReadWriteHandleOrSocket, BorrowedHandleOrSocket,
8 RawHandleOrSocket,
9};
10use std::io::{self, Read, Write};
11use std::{fmt, str};
12#[cfg(feature = "terminal-io")]
13use terminal_io::{DuplexTerminal, ReadTerminal, Terminal, TerminalColorSupport, WriteTerminal};
14#[cfg(feature = "layered-io")]
15use {
16 crate::ReadStrLayered,
17 layered_io::{Bufferable, HalfDuplexLayered, ReadLayered, Status, WriteLayered},
18 std::cmp::max,
19};
20#[cfg(not(windows))]
21use {
22 io_extras::os::rustix::{AsRawFd, AsReadWriteFd, RawFd},
23 std::os::fd::{AsFd, BorrowedFd},
24};
25
26pub struct Utf8Duplexer<Inner: HalfDuplex> {
28 pub(crate) inner: Inner,
30
31 pub(crate) input: Utf8Input,
33 pub(crate) output: Utf8Output,
34}
35
36impl<Inner: HalfDuplex> Utf8Duplexer<Inner> {
37 #[inline]
39 pub fn new(inner: Inner) -> Self {
40 Self {
41 inner,
42 input: Utf8Input::new(),
43 output: Utf8Output::new(),
44 }
45 }
46
47 #[inline]
49 pub fn into_inner(self) -> io::Result<Inner> {
50 Utf8Output::into_inner(self)
51 }
52}
53
54#[cfg(feature = "layered-io")]
55impl<Inner: HalfDuplexLayered> Utf8Duplexer<Inner> {
56 #[inline]
59 pub fn close_into_inner(self) -> io::Result<Inner> {
60 Utf8Output::into_inner(self)
61 }
62
63 #[inline]
66 pub fn abandon_into_inner(self) -> Inner {
67 Utf8Output::abandon_into_inner(self)
68 }
69}
70
71#[cfg(feature = "terminal-io")]
72impl<Inner: Duplex + DuplexTerminal> Terminal for Utf8Duplexer<Inner> {}
73
74#[cfg(feature = "terminal-io")]
75impl<Inner: Duplex + DuplexTerminal> ReadTerminal for Utf8Duplexer<Inner> {
76 #[inline]
77 fn is_line_by_line(&self) -> bool {
78 self.inner.is_line_by_line()
79 }
80
81 #[inline]
82 fn is_input_terminal(&self) -> bool {
83 self.inner.is_input_terminal()
84 }
85}
86
87#[cfg(feature = "terminal-io")]
88impl<Inner: Duplex + DuplexTerminal> WriteTerminal for Utf8Duplexer<Inner> {
89 #[inline]
90 fn color_support(&self) -> TerminalColorSupport {
91 self.inner.color_support()
92 }
93
94 #[inline]
95 fn color_preference(&self) -> bool {
96 self.inner.color_preference()
97 }
98
99 #[inline]
100 fn is_output_terminal(&self) -> bool {
101 self.inner.is_output_terminal()
102 }
103}
104
105#[cfg(feature = "terminal-io")]
106impl<Inner: HalfDuplex + DuplexTerminal> DuplexTerminal for Utf8Duplexer<Inner> {}
107
108impl<Inner: HalfDuplex> ReadStr for Utf8Duplexer<Inner> {
109 #[inline]
110 fn read_str(&mut self, buf: &mut str) -> io::Result<usize> {
111 Utf8Input::read_str(self, buf)
112 }
113
114 #[inline]
115 fn read_exact_str(&mut self, buf: &mut str) -> io::Result<()> {
116 Utf8Input::read_exact_str(self, buf)
117 }
118}
119
120#[cfg(feature = "layered-io")]
121impl<Inner: HalfDuplexLayered> ReadStrLayered for Utf8Duplexer<Inner> {
122 #[inline]
123 fn read_str_with_status(&mut self, buf: &mut str) -> io::Result<(usize, Status)> {
124 Utf8Input::read_str_with_status(self, buf)
125 }
126
127 #[inline]
128 fn read_exact_str_using_status(&mut self, buf: &mut str) -> io::Result<Status> {
129 Utf8Input::read_exact_str_using_status(self, buf)
130 }
131}
132
133#[cfg(feature = "layered-io")]
134impl<Inner: HalfDuplexLayered> ReadLayered for Utf8Duplexer<Inner> {
135 #[inline]
136 fn read_with_status(&mut self, buf: &mut [u8]) -> io::Result<(usize, Status)> {
137 Utf8Input::read_with_status(self, buf)
138 }
139
140 #[inline]
141 fn minimum_buffer_size(&self) -> usize {
142 Utf8Input::minimum_buffer_size(self)
143 }
144}
145
146#[cfg(feature = "layered-io")]
147impl<Inner: HalfDuplexLayered> Bufferable for Utf8Duplexer<Inner> {
148 #[inline]
149 fn abandon(&mut self) {
150 Utf8Input::abandon(self);
151 Utf8Output::abandon(self);
152 }
153
154 #[inline]
155 fn suggested_buffer_size(&self) -> usize {
156 max(
157 Utf8Input::suggested_buffer_size(self),
158 Utf8Output::suggested_buffer_size(self),
159 )
160 }
161}
162
163impl<Inner: HalfDuplex> Read for Utf8Duplexer<Inner> {
164 #[inline]
165 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
166 Utf8Input::read(self, buf)
167 }
168
169 #[inline]
170 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
171 Utf8Input::read_to_string(self, buf)
172 }
173}
174
175#[cfg(feature = "layered-io")]
176impl<Inner: HalfDuplexLayered> WriteLayered for Utf8Duplexer<Inner> {
177 #[inline]
178 fn close(&mut self) -> io::Result<()> {
179 Utf8Output::close(self)
180 }
181}
182
183impl<Inner: HalfDuplex> WriteStr for Utf8Duplexer<Inner> {
184 #[inline]
185 fn write_str(&mut self, s: &str) -> io::Result<()> {
186 Utf8Output::write_str(self, s)
187 }
188}
189
190impl<Inner: HalfDuplex> Duplex for Utf8Duplexer<Inner> {}
191
192impl<Inner: HalfDuplex> Write for Utf8Duplexer<Inner> {
193 #[inline]
194 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
195 Utf8Output::write(self, buf)
196 }
197
198 #[inline]
199 fn flush(&mut self) -> io::Result<()> {
200 Utf8Output::flush(self)
201 }
202}
203
204#[cfg(not(windows))]
205impl<Inner: HalfDuplex + AsRawFd> AsRawFd for Utf8Duplexer<Inner> {
206 #[inline]
207 fn as_raw_fd(&self) -> RawFd {
208 self.inner.as_raw_fd()
209 }
210}
211
212#[cfg(not(windows))]
213impl<Inner: HalfDuplex + AsFd> AsFd for Utf8Duplexer<Inner> {
214 #[inline]
215 fn as_fd(&self) -> BorrowedFd<'_> {
216 self.inner.as_fd()
217 }
218}
219
220#[cfg(windows)]
221impl<Inner: HalfDuplex + AsRawHandleOrSocket> AsRawHandleOrSocket for Utf8Duplexer<Inner> {
222 #[inline]
223 fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
224 self.inner.as_raw_handle_or_socket()
225 }
226}
227
228#[cfg(windows)]
229impl<Inner: HalfDuplex + AsHandleOrSocket> AsHandleOrSocket for Utf8Duplexer<Inner> {
230 #[inline]
231 fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
232 self.inner.as_handle_or_socket()
233 }
234}
235
236impl<Inner: HalfDuplex + fmt::Debug> fmt::Debug for Utf8Duplexer<Inner> {
237 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
238 let mut b = f.debug_struct("Utf8Duplexer");
239 b.field("inner", &self.inner);
240 b.finish()
241 }
242}
243
244#[cfg(not(windows))]
245impl<Inner: HalfDuplex + AsReadWriteFd> AsReadWriteFd for Utf8Duplexer<Inner> {
246 #[inline]
247 fn as_read_fd(&self) -> BorrowedFd<'_> {
248 self.inner.as_read_fd()
249 }
250
251 #[inline]
252 fn as_write_fd(&self) -> BorrowedFd<'_> {
253 self.inner.as_write_fd()
254 }
255}
256
257#[cfg(windows)]
258impl<Inner: HalfDuplex + AsReadWriteHandleOrSocket> AsReadWriteHandleOrSocket
259 for Utf8Duplexer<Inner>
260{
261 #[inline]
262 fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
263 self.inner.as_read_handle_or_socket()
264 }
265
266 #[inline]
267 fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
268 self.inner.as_write_handle_or_socket()
269 }
270}