1 use crate::sync::file::convert_systimespec;
2 use fs_set_times::SetTimes;
3 use std::any::Any;
4 use std::io::{self, IsTerminal, Read, Write};
5 use system_interface::io::ReadReady;
6 
7 use crate::{
8     Error, ErrorExt,
9     file::{FdFlags, FileType, WasiFile},
10 };
11 #[cfg(windows)]
12 use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
13 #[cfg(unix)]
14 use io_lifetimes::{AsFd, BorrowedFd};
15 #[cfg(windows)]
16 use io_lifetimes::{AsHandle, BorrowedHandle};
17 
18 pub struct Stdin(std::io::Stdin);
19 
stdin() -> Stdin20 pub fn stdin() -> Stdin {
21     Stdin(std::io::stdin())
22 }
23 
24 #[async_trait::async_trait]
25 impl WasiFile for Stdin {
as_any(&self) -> &dyn Any26     fn as_any(&self) -> &dyn Any {
27         self
28     }
29 
30     #[cfg(unix)]
pollable(&self) -> Option<rustix::fd::BorrowedFd<'_>>31     fn pollable(&self) -> Option<rustix::fd::BorrowedFd<'_>> {
32         Some(self.0.as_fd())
33     }
34 
35     #[cfg(windows)]
pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket>36     fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
37         Some(self.0.as_raw_handle_or_socket())
38     }
39 
get_filetype(&self) -> Result<FileType, Error>40     async fn get_filetype(&self) -> Result<FileType, Error> {
41         if self.isatty() {
42             Ok(FileType::CharacterDevice)
43         } else {
44             Ok(FileType::Unknown)
45         }
46     }
read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error>47     async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error> {
48         let n = self.0.lock().read_vectored(bufs)?;
49         Ok(n.try_into().map_err(|_| Error::range())?)
50     }
read_vectored_at<'a>( &self, _bufs: &mut [io::IoSliceMut<'a>], _offset: u64, ) -> Result<u64, Error>51     async fn read_vectored_at<'a>(
52         &self,
53         _bufs: &mut [io::IoSliceMut<'a>],
54         _offset: u64,
55     ) -> Result<u64, Error> {
56         Err(Error::seek_pipe())
57     }
seek(&self, _pos: std::io::SeekFrom) -> Result<u64, Error>58     async fn seek(&self, _pos: std::io::SeekFrom) -> Result<u64, Error> {
59         Err(Error::seek_pipe())
60     }
peek(&self, _buf: &mut [u8]) -> Result<u64, Error>61     async fn peek(&self, _buf: &mut [u8]) -> Result<u64, Error> {
62         Err(Error::seek_pipe())
63     }
set_times( &self, atime: Option<crate::SystemTimeSpec>, mtime: Option<crate::SystemTimeSpec>, ) -> Result<(), Error>64     async fn set_times(
65         &self,
66         atime: Option<crate::SystemTimeSpec>,
67         mtime: Option<crate::SystemTimeSpec>,
68     ) -> Result<(), Error> {
69         self.0
70             .set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
71         Ok(())
72     }
num_ready_bytes(&self) -> Result<u64, Error>73     fn num_ready_bytes(&self) -> Result<u64, Error> {
74         Ok(self.0.num_ready_bytes()?)
75     }
isatty(&self) -> bool76     fn isatty(&self) -> bool {
77         #[cfg(unix)]
78         return self.0.as_fd().is_terminal();
79         #[cfg(windows)]
80         return self.0.as_handle().is_terminal();
81     }
82 }
83 #[cfg(windows)]
84 impl AsHandle for Stdin {
as_handle(&self) -> BorrowedHandle<'_>85     fn as_handle(&self) -> BorrowedHandle<'_> {
86         self.0.as_handle()
87     }
88 }
89 #[cfg(windows)]
90 impl AsRawHandleOrSocket for Stdin {
91     #[inline]
as_raw_handle_or_socket(&self) -> RawHandleOrSocket92     fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
93         self.0.as_raw_handle_or_socket()
94     }
95 }
96 #[cfg(unix)]
97 impl AsFd for Stdin {
as_fd(&self) -> BorrowedFd<'_>98     fn as_fd(&self) -> BorrowedFd<'_> {
99         self.0.as_fd()
100     }
101 }
102 
103 macro_rules! wasi_file_write_impl {
104     ($ty:ty, $ident:ident) => {
105         #[async_trait::async_trait]
106         impl WasiFile for $ty {
107             fn as_any(&self) -> &dyn Any {
108                 self
109             }
110             #[cfg(unix)]
111             fn pollable(&self) -> Option<rustix::fd::BorrowedFd<'_>> {
112                 Some(self.0.as_fd())
113             }
114             #[cfg(windows)]
115             fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
116                 Some(self.0.as_raw_handle_or_socket())
117             }
118             async fn get_filetype(&self) -> Result<FileType, Error> {
119                 if self.isatty() {
120                     Ok(FileType::CharacterDevice)
121                 } else {
122                     Ok(FileType::Unknown)
123                 }
124             }
125             async fn get_fdflags(&self) -> Result<FdFlags, Error> {
126                 Ok(FdFlags::APPEND)
127             }
128             async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
129                 let mut io = self.0.lock();
130                 let n = io.write_vectored(bufs)?;
131                 // On a successful write additionally flush out the bytes to
132                 // handle stdio buffering done by libstd since WASI interfaces
133                 // here aren't buffered.
134                 io.flush()?;
135                 Ok(n.try_into().map_err(|_| {
136                     Error::range().context("converting write_vectored total length")
137                 })?)
138             }
139             async fn write_vectored_at<'a>(
140                 &self,
141                 _bufs: &[io::IoSlice<'a>],
142                 _offset: u64,
143             ) -> Result<u64, Error> {
144                 Err(Error::seek_pipe())
145             }
146             async fn seek(&self, _pos: std::io::SeekFrom) -> Result<u64, Error> {
147                 Err(Error::seek_pipe())
148             }
149             async fn set_times(
150                 &self,
151                 atime: Option<crate::SystemTimeSpec>,
152                 mtime: Option<crate::SystemTimeSpec>,
153             ) -> Result<(), Error> {
154                 self.0
155                     .set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
156                 Ok(())
157             }
158             fn isatty(&self) -> bool {
159                 self.0.is_terminal()
160             }
161         }
162         #[cfg(windows)]
163         impl AsHandle for $ty {
164             fn as_handle(&self) -> BorrowedHandle<'_> {
165                 self.0.as_handle()
166             }
167         }
168         #[cfg(unix)]
169         impl AsFd for $ty {
170             fn as_fd(&self) -> BorrowedFd<'_> {
171                 self.0.as_fd()
172             }
173         }
174         #[cfg(windows)]
175         impl AsRawHandleOrSocket for $ty {
176             #[inline]
177             fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
178                 self.0.as_raw_handle_or_socket()
179             }
180         }
181     };
182 }
183 
184 pub struct Stdout(std::io::Stdout);
185 
stdout() -> Stdout186 pub fn stdout() -> Stdout {
187     Stdout(std::io::stdout())
188 }
189 wasi_file_write_impl!(Stdout, Stdout);
190 
191 pub struct Stderr(std::io::Stderr);
192 
stderr() -> Stderr193 pub fn stderr() -> Stderr {
194     Stderr(std::io::stderr())
195 }
196 wasi_file_write_impl!(Stderr, Stderr);
197