Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi-common/src/sync/stdio.rs
1693 views
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
20
pub fn stdin() -> Stdin {
21
Stdin(std::io::stdin())
22
}
23
24
#[wiggle::async_trait]
25
impl WasiFile for Stdin {
26
fn as_any(&self) -> &dyn Any {
27
self
28
}
29
30
#[cfg(unix)]
31
fn pollable(&self) -> Option<rustix::fd::BorrowedFd<'_>> {
32
Some(self.0.as_fd())
33
}
34
35
#[cfg(windows)]
36
fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
37
Some(self.0.as_raw_handle_or_socket())
38
}
39
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
}
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
}
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
}
58
async fn seek(&self, _pos: std::io::SeekFrom) -> Result<u64, Error> {
59
Err(Error::seek_pipe())
60
}
61
async fn peek(&self, _buf: &mut [u8]) -> Result<u64, Error> {
62
Err(Error::seek_pipe())
63
}
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
}
73
fn num_ready_bytes(&self) -> Result<u64, Error> {
74
Ok(self.0.num_ready_bytes()?)
75
}
76
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 {
85
fn as_handle(&self) -> BorrowedHandle<'_> {
86
self.0.as_handle()
87
}
88
}
89
#[cfg(windows)]
90
impl AsRawHandleOrSocket for Stdin {
91
#[inline]
92
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 {
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
#[wiggle::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
186
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
193
pub fn stderr() -> Stderr {
194
Stderr(std::io::stderr())
195
}
196
wasi_file_write_impl!(Stderr, Stderr);
197
198