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