Files
wasmtime/crates/wasi-common/cap-std-sync/src/stdio.rs
Pat Hickey 56daa8a199 Use wiggle "trappable error" to implement wasi-common (#5279)
* convert wasi-common from defining its own error to using wiggle trappable error

* wasi-common impl crates: switch error strategy

* wasmtime-wasi: error is trappable, and no longer requires UserErrorConversion

* docs

* typo

* readdir: windows fixes

* fix windows scheduler errors

fun fact! the Send and Recv errors here that just had a `.context` on
them were previously not being captured in the downcasting either. They
need to be traps, and would have ended up that way by ommission, but
you'd never actually know that by reading the code!
2022-11-16 16:57:22 -08:00

193 lines
5.6 KiB
Rust

use crate::file::convert_systimespec;
use fs_set_times::SetTimes;
use io_lifetimes::AsFilelike;
use is_terminal::IsTerminal;
use std::any::Any;
use std::convert::TryInto;
use std::fs::File;
use std::io;
use std::io::{Read, Write};
use system_interface::io::ReadReady;
#[cfg(windows)]
use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
#[cfg(unix)]
use io_lifetimes::{AsFd, BorrowedFd};
#[cfg(windows)]
use io_lifetimes::{AsHandle, BorrowedHandle};
use wasi_common::{
file::{FdFlags, FileType, WasiFile},
Error, ErrorExt,
};
pub struct Stdin(std::io::Stdin);
pub fn stdin() -> Stdin {
Stdin(std::io::stdin())
}
#[async_trait::async_trait]
impl WasiFile for Stdin {
fn as_any(&self) -> &dyn Any {
self
}
#[cfg(unix)]
fn pollable(&self) -> Option<rustix::fd::BorrowedFd> {
Some(self.0.as_fd())
}
#[cfg(windows)]
fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
Some(self.0.as_raw_handle_or_socket())
}
async fn get_filetype(&mut self) -> Result<FileType, Error> {
if self.isatty() {
Ok(FileType::CharacterDevice)
} else {
Ok(FileType::Unknown)
}
}
async fn read_vectored<'a>(&mut self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error> {
let n = (&*self.0.as_filelike_view::<File>()).read_vectored(bufs)?;
Ok(n.try_into().map_err(|_| Error::range())?)
}
async fn read_vectored_at<'a>(
&mut self,
_bufs: &mut [io::IoSliceMut<'a>],
_offset: u64,
) -> Result<u64, Error> {
Err(Error::seek_pipe())
}
async fn seek(&mut self, _pos: std::io::SeekFrom) -> Result<u64, Error> {
Err(Error::seek_pipe())
}
async fn peek(&mut self, _buf: &mut [u8]) -> Result<u64, Error> {
Err(Error::seek_pipe())
}
async fn set_times(
&mut self,
atime: Option<wasi_common::SystemTimeSpec>,
mtime: Option<wasi_common::SystemTimeSpec>,
) -> Result<(), Error> {
self.0
.set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
Ok(())
}
async fn num_ready_bytes(&self) -> Result<u64, Error> {
Ok(self.0.num_ready_bytes()?)
}
fn isatty(&mut self) -> bool {
self.0.is_terminal()
}
}
#[cfg(windows)]
impl AsHandle for Stdin {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[cfg(windows)]
impl AsRawHandleOrSocket for Stdin {
#[inline]
fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
self.0.as_raw_handle_or_socket()
}
}
#[cfg(unix)]
impl AsFd for Stdin {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
macro_rules! wasi_file_write_impl {
($ty:ty, $ident:ident) => {
#[async_trait::async_trait]
impl WasiFile for $ty {
fn as_any(&self) -> &dyn Any {
self
}
#[cfg(unix)]
fn pollable(&self) -> Option<rustix::fd::BorrowedFd> {
Some(self.0.as_fd())
}
#[cfg(windows)]
fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
Some(self.0.as_raw_handle_or_socket())
}
async fn get_filetype(&mut self) -> Result<FileType, Error> {
if self.isatty() {
Ok(FileType::CharacterDevice)
} else {
Ok(FileType::Unknown)
}
}
async fn get_fdflags(&mut self) -> Result<FdFlags, Error> {
Ok(FdFlags::APPEND)
}
async fn write_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
let n = (&*self.0.as_filelike_view::<File>()).write_vectored(bufs)?;
Ok(n.try_into().map_err(|_| {
Error::range().context("converting write_vectored total length")
})?)
}
async fn write_vectored_at<'a>(
&mut self,
_bufs: &[io::IoSlice<'a>],
_offset: u64,
) -> Result<u64, Error> {
Err(Error::seek_pipe())
}
async fn seek(&mut self, _pos: std::io::SeekFrom) -> Result<u64, Error> {
Err(Error::seek_pipe())
}
async fn set_times(
&mut self,
atime: Option<wasi_common::SystemTimeSpec>,
mtime: Option<wasi_common::SystemTimeSpec>,
) -> Result<(), Error> {
self.0
.set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
Ok(())
}
fn isatty(&mut self) -> bool {
self.0.is_terminal()
}
}
#[cfg(windows)]
impl AsHandle for $ty {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[cfg(unix)]
impl AsFd for $ty {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
#[cfg(windows)]
impl AsRawHandleOrSocket for $ty {
#[inline]
fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
self.0.as_raw_handle_or_socket()
}
}
};
}
pub struct Stdout(std::io::Stdout);
pub fn stdout() -> Stdout {
Stdout(std::io::stdout())
}
wasi_file_write_impl!(Stdout, Stdout);
pub struct Stderr(std::io::Stderr);
pub fn stderr() -> Stderr {
Stderr(std::io::stderr())
}
wasi_file_write_impl!(Stderr, Stderr);