compio_fs/stdio/
windows.rs1use std::{
2 io::{self, IsTerminal, Read, Write},
3 os::windows::io::AsRawHandle,
4 pin::Pin,
5 sync::OnceLock,
6 task::Poll,
7};
8
9use compio_buf::{BufResult, IntoInner, IoBuf, IoBufMut};
10use compio_driver::{
11 AsRawFd, OpCode, OpType, RawFd, SharedFd,
12 op::{BufResultExt, Recv, Send},
13};
14use compio_io::{AsyncRead, AsyncWrite};
15use compio_runtime::Runtime;
16use windows_sys::Win32::System::IO::OVERLAPPED;
17
18#[cfg(doc)]
19use super::{stderr, stdin, stdout};
20
21struct StdRead<R: Read, B: IoBufMut> {
22 reader: R,
23 buffer: B,
24}
25
26impl<R: Read, B: IoBufMut> StdRead<R, B> {
27 pub fn new(reader: R, buffer: B) -> Self {
28 Self { reader, buffer }
29 }
30}
31
32impl<R: Read, B: IoBufMut> OpCode for StdRead<R, B> {
33 fn op_type(&self) -> OpType {
34 OpType::Blocking
35 }
36
37 unsafe fn operate(self: Pin<&mut Self>, _optr: *mut OVERLAPPED) -> Poll<io::Result<usize>> {
38 let this = self.get_unchecked_mut();
39 let slice = this.buffer.as_mut_slice();
40 #[cfg(feature = "read_buf")]
41 {
42 let mut buf = io::BorrowedBuf::from(slice);
43 let mut cursor = buf.unfilled();
44 this.reader.read_buf(cursor.reborrow())?;
45 Poll::Ready(Ok(cursor.written()))
46 }
47 #[cfg(not(feature = "read_buf"))]
48 {
49 use std::mem::MaybeUninit;
50
51 slice.fill(MaybeUninit::new(0));
52 this.reader
53 .read(std::slice::from_raw_parts_mut(
54 this.buffer.as_buf_mut_ptr(),
55 this.buffer.buf_capacity(),
56 ))
57 .into()
58 }
59 }
60}
61
62impl<R: Read, B: IoBufMut> IntoInner for StdRead<R, B> {
63 type Inner = B;
64
65 fn into_inner(self) -> Self::Inner {
66 self.buffer
67 }
68}
69
70struct StdWrite<W: Write, B: IoBuf> {
71 writer: W,
72 buffer: B,
73}
74
75impl<W: Write, B: IoBuf> StdWrite<W, B> {
76 pub fn new(writer: W, buffer: B) -> Self {
77 Self { writer, buffer }
78 }
79}
80
81impl<W: Write, B: IoBuf> OpCode for StdWrite<W, B> {
82 fn op_type(&self) -> OpType {
83 OpType::Blocking
84 }
85
86 unsafe fn operate(self: Pin<&mut Self>, _optr: *mut OVERLAPPED) -> Poll<io::Result<usize>> {
87 let this = self.get_unchecked_mut();
88 let slice = this.buffer.as_slice();
89 this.writer.write(slice).into()
90 }
91}
92
93impl<W: Write, B: IoBuf> IntoInner for StdWrite<W, B> {
94 type Inner = B;
95
96 fn into_inner(self) -> Self::Inner {
97 self.buffer
98 }
99}
100
101static STDIN_ISATTY: OnceLock<bool> = OnceLock::new();
102
103#[derive(Debug, Clone)]
107pub struct Stdin {
108 fd: SharedFd<RawFd>,
109 isatty: bool,
110}
111
112impl Stdin {
113 pub(crate) fn new() -> Self {
114 let stdin = io::stdin();
115 let isatty = *STDIN_ISATTY.get_or_init(|| {
116 stdin.is_terminal()
117 || Runtime::with_current(|r| r.attach(stdin.as_raw_handle() as _)).is_err()
118 });
119 Self {
120 fd: SharedFd::new(stdin.as_raw_handle() as _),
121 isatty,
122 }
123 }
124}
125
126impl AsyncRead for Stdin {
127 async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
128 if self.isatty {
129 let op = StdRead::new(io::stdin(), buf);
130 compio_runtime::submit(op).await.into_inner()
131 } else {
132 let op = Recv::new(self.fd.clone(), buf);
133 compio_runtime::submit(op).await.into_inner()
134 }
135 .map_advanced()
136 }
137}
138
139impl AsRawFd for Stdin {
140 fn as_raw_fd(&self) -> RawFd {
141 self.fd.as_raw_fd()
142 }
143}
144
145static STDOUT_ISATTY: OnceLock<bool> = OnceLock::new();
146
147#[derive(Debug, Clone)]
151pub struct Stdout {
152 fd: SharedFd<RawFd>,
153 isatty: bool,
154}
155
156impl Stdout {
157 pub(crate) fn new() -> Self {
158 let stdout = io::stdout();
159 let isatty = *STDOUT_ISATTY.get_or_init(|| {
160 stdout.is_terminal()
161 || Runtime::with_current(|r| r.attach(stdout.as_raw_handle() as _)).is_err()
162 });
163 Self {
164 fd: SharedFd::new(stdout.as_raw_handle() as _),
165 isatty,
166 }
167 }
168}
169
170impl AsyncWrite for Stdout {
171 async fn write<T: IoBuf>(&mut self, buf: T) -> BufResult<usize, T> {
172 if self.isatty {
173 let op = StdWrite::new(io::stdout(), buf);
174 compio_runtime::submit(op).await.into_inner()
175 } else {
176 let op = Send::new(self.fd.clone(), buf);
177 compio_runtime::submit(op).await.into_inner()
178 }
179 }
180
181 async fn flush(&mut self) -> io::Result<()> {
182 Ok(())
183 }
184
185 async fn shutdown(&mut self) -> io::Result<()> {
186 self.flush().await
187 }
188}
189
190impl AsRawFd for Stdout {
191 fn as_raw_fd(&self) -> RawFd {
192 self.fd.as_raw_fd()
193 }
194}
195
196static STDERR_ISATTY: OnceLock<bool> = OnceLock::new();
197
198#[derive(Debug, Clone)]
202pub struct Stderr {
203 fd: SharedFd<RawFd>,
204 isatty: bool,
205}
206
207impl Stderr {
208 pub(crate) fn new() -> Self {
209 let stderr = io::stderr();
210 let isatty = *STDERR_ISATTY.get_or_init(|| {
211 stderr.is_terminal()
212 || Runtime::with_current(|r| r.attach(stderr.as_raw_handle() as _)).is_err()
213 });
214 Self {
215 fd: SharedFd::new(stderr.as_raw_handle() as _),
216 isatty,
217 }
218 }
219}
220
221impl AsyncWrite for Stderr {
222 async fn write<T: IoBuf>(&mut self, buf: T) -> BufResult<usize, T> {
223 if self.isatty {
224 let op = StdWrite::new(io::stderr(), buf);
225 compio_runtime::submit(op).await.into_inner()
226 } else {
227 let op = Send::new(self.fd.clone(), buf);
228 compio_runtime::submit(op).await.into_inner()
229 }
230 }
231
232 async fn flush(&mut self) -> io::Result<()> {
233 Ok(())
234 }
235
236 async fn shutdown(&mut self) -> io::Result<()> {
237 self.flush().await
238 }
239}
240
241impl AsRawFd for Stderr {
242 fn as_raw_fd(&self) -> RawFd {
243 self.fd.as_raw_fd()
244 }
245}