wasi_tokio/
file.rs

1use crate::block_on_dummy_executor;
2#[cfg(windows)]
3use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
4#[cfg(not(windows))]
5use io_lifetimes::AsFd;
6use std::any::Any;
7use std::borrow::Borrow;
8use std::io;
9use wasi_common::{
10    file::{Advice, FdFlags, FileType, Filestat, WasiFile},
11    Error,
12};
13
14pub struct File(wasi_cap_std_sync::file::File);
15
16impl File {
17    pub(crate) fn from_inner(file: wasi_cap_std_sync::file::File) -> Self {
18        File(file)
19    }
20    pub fn from_cap_std(file: cap_std::fs::File) -> Self {
21        Self::from_inner(wasi_cap_std_sync::file::File::from_cap_std(file))
22    }
23}
24
25pub struct TcpListener(wasi_cap_std_sync::net::TcpListener);
26
27impl TcpListener {
28    pub(crate) fn from_inner(listener: wasi_cap_std_sync::net::TcpListener) -> Self {
29        TcpListener(listener)
30    }
31    pub fn from_cap_std(listener: cap_std::net::TcpListener) -> Self {
32        Self::from_inner(wasi_cap_std_sync::net::TcpListener::from_cap_std(listener))
33    }
34}
35
36pub struct TcpStream(wasi_cap_std_sync::net::TcpStream);
37
38impl TcpStream {
39    pub(crate) fn from_inner(stream: wasi_cap_std_sync::net::TcpStream) -> Self {
40        TcpStream(stream)
41    }
42    pub fn from_cap_std(stream: cap_std::net::TcpStream) -> Self {
43        Self::from_inner(wasi_cap_std_sync::net::TcpStream::from_cap_std(stream))
44    }
45}
46
47#[cfg(unix)]
48pub struct UnixListener(wasi_cap_std_sync::net::UnixListener);
49
50#[cfg(unix)]
51impl UnixListener {
52    pub(crate) fn from_inner(listener: wasi_cap_std_sync::net::UnixListener) -> Self {
53        UnixListener(listener)
54    }
55    pub fn from_cap_std(listener: cap_std::os::unix::net::UnixListener) -> Self {
56        Self::from_inner(wasi_cap_std_sync::net::UnixListener::from_cap_std(listener))
57    }
58}
59
60#[cfg(unix)]
61pub struct UnixStream(wasi_cap_std_sync::net::UnixStream);
62
63#[cfg(unix)]
64impl UnixStream {
65    fn from_inner(stream: wasi_cap_std_sync::net::UnixStream) -> Self {
66        UnixStream(stream)
67    }
68    pub fn from_cap_std(stream: cap_std::os::unix::net::UnixStream) -> Self {
69        Self::from_inner(wasi_cap_std_sync::net::UnixStream::from_cap_std(stream))
70    }
71}
72
73pub struct Stdin(wasi_cap_std_sync::stdio::Stdin);
74
75pub fn stdin() -> Stdin {
76    Stdin(wasi_cap_std_sync::stdio::stdin())
77}
78
79pub struct Stdout(wasi_cap_std_sync::stdio::Stdout);
80
81pub fn stdout() -> Stdout {
82    Stdout(wasi_cap_std_sync::stdio::stdout())
83}
84
85pub struct Stderr(wasi_cap_std_sync::stdio::Stderr);
86
87pub fn stderr() -> Stderr {
88    Stderr(wasi_cap_std_sync::stdio::stderr())
89}
90
91macro_rules! wasi_file_impl {
92    ($ty:ty) => {
93        #[wiggle::async_trait]
94        impl WasiFile for $ty {
95            fn as_any(&self) -> &dyn Any {
96                self
97            }
98            #[cfg(unix)]
99            fn pollable(&self) -> Option<rustix::fd::BorrowedFd> {
100                Some(self.0.as_fd())
101            }
102            #[cfg(windows)]
103            fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
104                Some(self.0.as_raw_handle_or_socket())
105            }
106            async fn datasync(&self) -> Result<(), Error> {
107                block_on_dummy_executor(|| self.0.datasync())
108            }
109            async fn sync(&self) -> Result<(), Error> {
110                block_on_dummy_executor(|| self.0.sync())
111            }
112            async fn get_filetype(&self) -> Result<FileType, Error> {
113                block_on_dummy_executor(|| self.0.get_filetype())
114            }
115            async fn get_fdflags(&self) -> Result<FdFlags, Error> {
116                block_on_dummy_executor(|| self.0.get_fdflags())
117            }
118            async fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> {
119                block_on_dummy_executor(|| self.0.set_fdflags(fdflags))
120            }
121            async fn get_filestat(&self) -> Result<Filestat, Error> {
122                block_on_dummy_executor(|| self.0.get_filestat())
123            }
124            async fn set_filestat_size(&self, size: u64) -> Result<(), Error> {
125                block_on_dummy_executor(move || self.0.set_filestat_size(size))
126            }
127            async fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
128                block_on_dummy_executor(move || self.0.advise(offset, len, advice))
129            }
130            async fn read_vectored<'a>(
131                &self,
132                bufs: &mut [io::IoSliceMut<'a>],
133            ) -> Result<u64, Error> {
134                block_on_dummy_executor(move || self.0.read_vectored(bufs))
135            }
136            async fn read_vectored_at<'a>(
137                &self,
138                bufs: &mut [io::IoSliceMut<'a>],
139                offset: u64,
140            ) -> Result<u64, Error> {
141                block_on_dummy_executor(move || self.0.read_vectored_at(bufs, offset))
142            }
143            async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
144                block_on_dummy_executor(move || self.0.write_vectored(bufs))
145            }
146            async fn write_vectored_at<'a>(
147                &self,
148                bufs: &[io::IoSlice<'a>],
149                offset: u64,
150            ) -> Result<u64, Error> {
151                block_on_dummy_executor(move || self.0.write_vectored_at(bufs, offset))
152            }
153            async fn seek(&self, pos: std::io::SeekFrom) -> Result<u64, Error> {
154                block_on_dummy_executor(move || self.0.seek(pos))
155            }
156            async fn peek(&self, buf: &mut [u8]) -> Result<u64, Error> {
157                block_on_dummy_executor(move || self.0.peek(buf))
158            }
159            async fn set_times(
160                &self,
161                atime: Option<wasi_common::SystemTimeSpec>,
162                mtime: Option<wasi_common::SystemTimeSpec>,
163            ) -> Result<(), Error> {
164                block_on_dummy_executor(move || self.0.set_times(atime, mtime))
165            }
166            fn num_ready_bytes(&self) -> Result<u64, Error> {
167                self.0.num_ready_bytes()
168            }
169            fn isatty(&self) -> bool {
170                self.0.isatty()
171            }
172
173            #[cfg(not(windows))]
174            async fn readable(&self) -> Result<(), Error> {
175                // The Inner impls OwnsRaw, which asserts exclusive use of the handle by the owned object.
176                // AsyncFd needs to wrap an owned `impl std::os::unix::io::AsRawFd`. Rather than introduce
177                // mutability to let it own the `Inner`, we are depending on the `&mut self` bound on this
178                // async method to ensure this is the only Future which can access the RawFd during the
179                // lifetime of the AsyncFd.
180                use std::os::unix::io::AsRawFd;
181                use tokio::io::{unix::AsyncFd, Interest};
182                let rawfd = self.0.borrow().as_fd().as_raw_fd();
183                match AsyncFd::with_interest(rawfd, Interest::READABLE) {
184                    Ok(asyncfd) => {
185                        let _ = asyncfd.readable().await?;
186                        Ok(())
187                    }
188                    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
189                        // if e is EPERM, this file isnt supported by epoll because it is immediately
190                        // available for reading:
191                        Ok(())
192                    }
193                    Err(e) => Err(e.into()),
194                }
195            }
196
197            #[cfg(not(windows))]
198            async fn writable(&self) -> Result<(), Error> {
199                // The Inner impls OwnsRaw, which asserts exclusive use of the handle by the owned object.
200                // AsyncFd needs to wrap an owned `impl std::os::unix::io::AsRawFd`. Rather than introduce
201                // mutability to let it own the `Inner`, we are depending on the `&mut self` bound on this
202                // async method to ensure this is the only Future which can access the RawFd during the
203                // lifetime of the AsyncFd.
204                use std::os::unix::io::AsRawFd;
205                use tokio::io::{unix::AsyncFd, Interest};
206                let rawfd = self.0.borrow().as_fd().as_raw_fd();
207                match AsyncFd::with_interest(rawfd, Interest::WRITABLE) {
208                    Ok(asyncfd) => {
209                        let _ = asyncfd.writable().await?;
210                        Ok(())
211                    }
212                    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
213                        // if e is EPERM, this file isnt supported by epoll because it is immediately
214                        // available for writing:
215                        Ok(())
216                    }
217                    Err(e) => Err(e.into()),
218                }
219            }
220
221            async fn sock_accept(&self, fdflags: FdFlags) -> Result<Box<dyn WasiFile>, Error> {
222                block_on_dummy_executor(|| self.0.sock_accept(fdflags))
223            }
224        }
225        #[cfg(windows)]
226        impl AsRawHandleOrSocket for $ty {
227            #[inline]
228            fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
229                self.0.borrow().as_raw_handle_or_socket()
230            }
231        }
232    };
233}
234
235wasi_file_impl!(File);
236wasi_file_impl!(TcpListener);
237wasi_file_impl!(TcpStream);
238#[cfg(unix)]
239wasi_file_impl!(UnixListener);
240#[cfg(unix)]
241wasi_file_impl!(UnixStream);
242wasi_file_impl!(Stdin);
243wasi_file_impl!(Stdout);
244wasi_file_impl!(Stderr);