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