From b87908de9b3520a79ff936d21fa348ff83ef246d Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 17 Nov 2020 15:23:26 -0800 Subject: [PATCH] wasi-c2: rewrite wasi-common in terms of system-interface --- Cargo.lock | 49 ++- Cargo.toml | 1 + crates/wasi-c2/Cargo.toml | 35 ++ crates/wasi-c2/build.rs | 8 + crates/wasi-c2/src/ctx.rs | 26 ++ crates/wasi-c2/src/error.rs | 151 ++++++++ crates/wasi-c2/src/file.rs | 53 +++ crates/wasi-c2/src/lib.rs | 8 + crates/wasi-c2/src/snapshots/mod.rs | 1 + crates/wasi-c2/src/snapshots/preview_1.rs | 424 ++++++++++++++++++++++ crates/wasi-c2/src/table.rs | 46 +++ 11 files changed, 801 insertions(+), 1 deletion(-) create mode 100644 crates/wasi-c2/Cargo.toml create mode 100644 crates/wasi-c2/build.rs create mode 100644 crates/wasi-c2/src/ctx.rs create mode 100644 crates/wasi-c2/src/error.rs create mode 100644 crates/wasi-c2/src/file.rs create mode 100644 crates/wasi-c2/src/lib.rs create mode 100644 crates/wasi-c2/src/snapshots/mod.rs create mode 100644 crates/wasi-c2/src/snapshots/preview_1.rs create mode 100644 crates/wasi-c2/src/table.rs diff --git a/Cargo.lock b/Cargo.lock index aabea2ee2b..88a1f4a69b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1458,6 +1458,19 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" +[[package]] +name = "posish" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a81e5017f1c873447782cd776e6ec307af670ecad29e934042005a0dec6864dd" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "errno", + "itoa", + "libc", +] + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -1992,6 +2005,16 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "system-interface" +version = "0.0.1-alpha.0" +dependencies = [ + "atty", + "posish", + "winapi", + "winx 0.20.0", +] + [[package]] name = "target-lexicon" version = "0.11.1" @@ -2283,6 +2306,19 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasi-c2" +version = "0.21.0" +dependencies = [ + "anyhow", + "getrandom 0.2.0", + "libc", + "system-interface", + "thiserror", + "tracing", + "wiggle", +] + [[package]] name = "wasi-common" version = "0.21.0" @@ -2298,7 +2334,7 @@ dependencies = [ "tracing", "wiggle", "winapi", - "winx", + "winx 0.21.0", "yanix", ] @@ -2810,6 +2846,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winx" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25e4ae373f2f2f7f5f187974ed315719ce74160859027c80deb1f68b3c0c966" +dependencies = [ + "bitflags", + "cvt", + "winapi", +] + [[package]] name = "winx" version = "0.21.0" diff --git a/Cargo.toml b/Cargo.toml index 796d74dbdf..54871d188b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ members = [ "crates/misc/rust", "crates/wiggle", "crates/wiggle/wasmtime", + "crates/wasi-c2", "examples/fib-debug/wasm", "examples/wasi/wasm", "examples/wasi-fs/wasm", diff --git a/crates/wasi-c2/Cargo.toml b/crates/wasi-c2/Cargo.toml new file mode 100644 index 0000000000..66b85429e6 --- /dev/null +++ b/crates/wasi-c2/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "wasi-c2" +version = "0.21.0" +authors = ["The Wasmtime Project Developers"] +description = "WASI implementation in Rust" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +keywords = ["webassembly", "wasm"] +repository = "https://github.com/bytecodealliance/wasmtime" +readme = "README.md" +edition = "2018" +include = ["src/**/*", "LICENSE", "build.rs"] +build = "build.rs" + +[dependencies] +anyhow = "1.0" +thiserror = "1.0" +libc = "0.2" +getrandom = { version = "0.2.0", features = ["std"] } +wiggle = { path = "../wiggle", default-features = false, version = "0.21.0" } +tracing = "0.1.19" +system-interface = { path = "../../../system-interface" } + +[badges] +maintenance = { status = "actively-developed" } + +[features] +default = ["trace_log"] +# This feature enables the `tracing` logs in the calls to target the `log` +# ecosystem of backends (e.g. `env_logger`. Disable this if you want to use +# `tracing-subscriber`. +trace_log = [ "wiggle/tracing_log", "tracing/log" ] +# Need to make the wiggle_metadata feature available to consumers of this +# crate if they want the snapshots to have metadata available. +wiggle_metadata = ["wiggle/wiggle_metadata"] diff --git a/crates/wasi-c2/build.rs b/crates/wasi-c2/build.rs new file mode 100644 index 0000000000..fdb3f82111 --- /dev/null +++ b/crates/wasi-c2/build.rs @@ -0,0 +1,8 @@ +// Tell any dependencies, if necessary, where our WASI submodule is so they can +// use the same witx files if they want. +fn main() { + let cwd = std::env::current_dir().unwrap(); + let wasi = cwd.join("..").join("wasi-common").join("WASI"); + println!("cargo:wasi={}", wasi.display()); + println!("cargo:rustc-env=WASI_ROOT={}", wasi.display()); +} diff --git a/crates/wasi-c2/src/ctx.rs b/crates/wasi-c2/src/ctx.rs new file mode 100644 index 0000000000..d0cdfc1b5c --- /dev/null +++ b/crates/wasi-c2/src/ctx.rs @@ -0,0 +1,26 @@ +use crate::table::Table; +use std::cell::{RefCell, RefMut}; +use std::rc::Rc; + +pub struct WasiCtx { + table: Rc>, +} + +impl WasiCtx { + pub fn new() -> Self { + WasiCtx { + table: Rc::new(RefCell::new(Table::new())), + } + } + + pub fn table(&self) -> RefMut { + self.table.borrow_mut() + } +} + +pub trait WasiDir {} + +pub(crate) struct DirEntry { + pub(crate) flags: u32, + pub(crate) dir: Box, +} diff --git a/crates/wasi-c2/src/error.rs b/crates/wasi-c2/src/error.rs new file mode 100644 index 0000000000..20b0de9d00 --- /dev/null +++ b/crates/wasi-c2/src/error.rs @@ -0,0 +1,151 @@ +use crate::file::FileCaps; +use thiserror::Error; + +/// Internal error type for the `wasi-common` crate. +/// Contains variants of the WASI `$errno` type are added according to what is actually used internally by +/// the crate. Not all values are represented presently. +#[derive(Debug, Error)] +pub enum Error { + #[error("Wiggle GuestError: {0}")] + Guest(#[from] wiggle::GuestError), + #[error("TryFromIntError: {0}")] + TryFromInt(#[from] std::num::TryFromIntError), + #[error("Utf8Error: {0}")] + Utf8(#[from] std::str::Utf8Error), + #[error("GetRandom: {0}")] + GetRandom(#[from] getrandom::Error), + + /// Errno::Notcapable: Extension: Capabilities insufficient + #[error("File not capable: {0}")] + FileNotCapable(FileCaps), + + /// The host OS may return an io error that doesn't match one of the + /// wasi errno variants we expect. We do not expose the details of this + /// error to the user. + #[error("Unexpected IoError: {0}")] + UnexpectedIo(#[source] std::io::Error), + + // Below this, all variants are from the `$errno` type: + /// Errno::TooBig: Argument list too long + #[error("TooBig: Argument list too long")] + TooBig, + /// Errno::Acces: Permission denied + #[error("Acces: Permission denied")] + Acces, + /// Errno::Badf: Bad file descriptor + #[error("Badf: Bad file descriptor")] + Badf, + /// Errno::Busy: Device or resource busy + #[error("Busy: Device or resource busy")] + Busy, + /// Errno::Exist: File exists + #[error("Exist: File exists")] + Exist, + /// Errno::Fault: Bad address + #[error("Fault: Bad address")] + Fault, + /// Errno::Fbig: File too large + #[error("Fbig: File too large")] + Fbig, + /// Errno::Ilseq: Illegal byte sequence + #[error("Ilseq: Illegal byte sequence")] + Ilseq, + /// Errno::Inval: Invalid argument + #[error("Inval: Invalid argument")] + Inval, + /// Errno::Io: I/O error + #[error("Io: I/o error")] + Io, + /// Errno::Isdir: Is a directory + #[error("Isdir: Is a directory")] + Isdir, + /// Errno::Loop: Too many levels of symbolic links + #[error("Loop: Too many levels of symbolic links")] + Loop, + /// Errno::Mfile: File descriptor value too large + #[error("Mfile: File descriptor value too large")] + Mfile, + /// Errno::Mlink: Too many links + #[error("Mlink: Too many links")] + Mlink, + /// Errno::Nametoolong: Filename too long + #[error("Nametoolong: Filename too long")] + Nametoolong, + /// Errno::Nfile: Too many files open in system + #[error("Nfile: Too many files open in system")] + Nfile, + /// Errno::Noent: No such file or directory + #[error("Noent: No such file or directory")] + Noent, + /// Errno::Nomem: Not enough space + #[error("Nomem: Not enough space")] + Nomem, + /// Errno::Nospc: No space left on device + #[error("Nospc: No space left on device")] + Nospc, + /// Errno::Notdir: Not a directory or a symbolic link to a directory. + #[error("Notdir: Not a directory or a symbolic link to a directory")] + Notdir, + /// Errno::Notempty: Directory not empty. + #[error("Notempty: Directory not empty")] + Notempty, + /// Errno::Notsup: Not supported, or operation not supported on socket. + #[error("Notsup: Not supported, or operation not supported on socket")] + Notsup, + /// Errno::Overflow: Value too large to be stored in data type. + #[error("Overflow: Value too large to be stored in data type")] + Overflow, + /// Errno::Pipe: Broken pipe + #[error("Pipe: Broken pipe")] + Pipe, + /// Errno::Perm: Operation not permitted + #[error("Perm: Operation not permitted")] + Perm, + /// Errno::Spipe: Invalid seek + #[error("Spipe: Invalid seek")] + Spipe, +} + +impl From for Error { + fn from(_err: std::convert::Infallible) -> Self { + unreachable!("should be impossible: From") + } +} + +use std::io; +impl From for Error { + fn from(err: io::Error) -> Self { + match err.raw_os_error() { + Some(code) => match code { + libc::EPIPE => Self::Pipe, + libc::EPERM => Self::Perm, + libc::ENOENT => Self::Noent, + libc::ENOMEM => Self::Nomem, + libc::E2BIG => Self::TooBig, + libc::EIO => Self::Io, + libc::EBADF => Self::Badf, + libc::EBUSY => Self::Busy, + libc::EACCES => Self::Acces, + libc::EFAULT => Self::Fault, + libc::ENOTDIR => Self::Notdir, + libc::EISDIR => Self::Isdir, + libc::EINVAL => Self::Inval, + libc::EEXIST => Self::Exist, + libc::EFBIG => Self::Fbig, + libc::ENOSPC => Self::Nospc, + libc::ESPIPE => Self::Spipe, + libc::EMFILE => Self::Mfile, + libc::EMLINK => Self::Mlink, + libc::ENAMETOOLONG => Self::Nametoolong, + libc::ENFILE => Self::Nfile, + libc::ENOTEMPTY => Self::Notempty, + libc::ELOOP => Self::Loop, + libc::EOVERFLOW => Self::Overflow, + libc::EILSEQ => Self::Ilseq, + libc::ENOTSUP => Self::Notsup, + _ => Self::UnexpectedIo(err), + }, + None => Self::UnexpectedIo(err), + } + } +} diff --git a/crates/wasi-c2/src/file.rs b/crates/wasi-c2/src/file.rs new file mode 100644 index 0000000000..5f8116a84b --- /dev/null +++ b/crates/wasi-c2/src/file.rs @@ -0,0 +1,53 @@ +use crate::Error; +use std::ops::Deref; +use system_interface::fs::FileIoExt; + +pub trait WasiFile: FileIoExt {} + +pub(crate) struct FileEntry { + pub(crate) base_caps: FileCaps, + pub(crate) inheriting_caps: FileCaps, + pub(crate) file: Box, +} + +impl FileEntry { + pub fn get_cap(&self, caps: FileCaps) -> Result<&dyn WasiFile, Error> { + if self.base_caps.contains(&caps) && self.inheriting_caps.contains(&caps) { + Ok(self.file.deref()) + } else { + Err(Error::FileNotCapable(caps)) + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct FileCaps { + flags: u32, +} + +impl FileCaps { + pub fn empty() -> Self { + FileCaps { flags: 0 } + } + + /// Checks if `other` is a subset of those capabilties: + pub fn contains(&self, other: &Self) -> bool { + self.flags & other.flags == other.flags + } + + pub const DATASYNC: Self = FileCaps { flags: 1 }; + pub const READ: Self = FileCaps { flags: 2 }; + pub const SEEK: Self = FileCaps { flags: 4 }; + pub const FDSTAT_SET_FLAGS: Self = FileCaps { flags: 8 }; + pub const SYNC: Self = FileCaps { flags: 16 }; + pub const TELL: Self = FileCaps { flags: 32 }; + pub const WRITE: Self = FileCaps { flags: 64 }; + pub const ADVISE: Self = FileCaps { flags: 128 }; + pub const ALLOCATE: Self = FileCaps { flags: 256 }; +} + +impl std::fmt::Display for FileCaps { + fn fmt(&self, _f: &mut std::fmt::Formatter) -> std::fmt::Result { + todo!() + } +} diff --git a/crates/wasi-c2/src/lib.rs b/crates/wasi-c2/src/lib.rs new file mode 100644 index 0000000000..33502caf46 --- /dev/null +++ b/crates/wasi-c2/src/lib.rs @@ -0,0 +1,8 @@ +mod ctx; +mod error; +mod file; +pub mod snapshots; +pub mod table; + +pub use ctx::WasiCtx; +pub use error::Error; diff --git a/crates/wasi-c2/src/snapshots/mod.rs b/crates/wasi-c2/src/snapshots/mod.rs new file mode 100644 index 0000000000..1508cc068d --- /dev/null +++ b/crates/wasi-c2/src/snapshots/mod.rs @@ -0,0 +1 @@ +pub mod preview_1; diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs new file mode 100644 index 0000000000..6b8b262ff1 --- /dev/null +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -0,0 +1,424 @@ +#![allow(unused_variables)] +use crate::file::{FileCaps, FileEntry}; +use crate::{Error, WasiCtx}; +use std::cell::RefMut; +use tracing::debug; +use wiggle::GuestPtr; + +wiggle::from_witx!({ + witx: ["$WASI_ROOT/phases/snapshot/witx/wasi_snapshot_preview1.witx"], + ctx: WasiCtx, + errors: { errno => Error }, +}); + +impl wiggle::GuestErrorType for types::Errno { + fn success() -> Self { + Self::Success + } +} + +impl types::GuestErrorConversion for WasiCtx { + fn into_errno(&self, e: wiggle::GuestError) -> types::Errno { + debug!("Guest error: {:?}", e); + e.into() + } +} + +impl types::UserErrorConversion for WasiCtx { + fn errno_from_error(&self, e: Error) -> types::Errno { + debug!("Error: {:?}", e); + e.into() + } +} + +impl From for types::Errno { + fn from(e: Error) -> types::Errno { + use types::Errno; + match e { + Error::Guest(e) => e.into(), + Error::TryFromInt(_) => Errno::Overflow, + Error::Utf8(_) => Errno::Ilseq, + Error::UnexpectedIo(_) => Errno::Io, + Error::GetRandom(_) => Errno::Io, + Error::TooBig => Errno::TooBig, + Error::Acces => Errno::Acces, + Error::Badf => Errno::Badf, + Error::Busy => Errno::Busy, + Error::Exist => Errno::Exist, + Error::Fault => Errno::Fault, + Error::Fbig => Errno::Fbig, + Error::Ilseq => Errno::Ilseq, + Error::Inval => Errno::Inval, + Error::Io => Errno::Io, + Error::Isdir => Errno::Isdir, + Error::Loop => Errno::Loop, + Error::Mfile => Errno::Mfile, + Error::Mlink => Errno::Mlink, + Error::Nametoolong => Errno::Nametoolong, + Error::Nfile => Errno::Nfile, + Error::Noent => Errno::Noent, + Error::Nomem => Errno::Nomem, + Error::Nospc => Errno::Nospc, + Error::Notdir => Errno::Notdir, + Error::Notempty => Errno::Notempty, + Error::Notsup => Errno::Notsup, + Error::Overflow => Errno::Overflow, + Error::Pipe => Errno::Pipe, + Error::Perm => Errno::Perm, + Error::Spipe => Errno::Spipe, + Error::FileNotCapable { .. } => Errno::Notcapable, + } + } +} + +impl From for types::Errno { + fn from(err: wiggle::GuestError) -> Self { + use wiggle::GuestError::*; + match err { + InvalidFlagValue { .. } => Self::Inval, + InvalidEnumValue { .. } => Self::Inval, + PtrOverflow { .. } => Self::Fault, + PtrOutOfBounds { .. } => Self::Fault, + PtrNotAligned { .. } => Self::Inval, + PtrBorrowed { .. } => Self::Fault, + InvalidUtf8 { .. } => Self::Ilseq, + TryFromIntError { .. } => Self::Overflow, + InFunc { .. } => Self::Inval, + InDataField { .. } => Self::Inval, + SliceLengthsDiffer { .. } => Self::Fault, + BorrowCheckerOutOfHandles { .. } => Self::Fault, + } + } +} + +impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { + fn args_get<'b>( + &self, + argv: &GuestPtr<'b, GuestPtr<'b, u8>>, + argv_buf: &GuestPtr<'b, u8>, + ) -> Result<(), Error> { + unimplemented!() + } + + fn args_sizes_get(&self) -> Result<(types::Size, types::Size), Error> { + unimplemented!() + } + + fn environ_get<'b>( + &self, + environ: &GuestPtr<'b, GuestPtr<'b, u8>>, + environ_buf: &GuestPtr<'b, u8>, + ) -> Result<(), Error> { + unimplemented!() + } + + fn environ_sizes_get(&self) -> Result<(types::Size, types::Size), Error> { + unimplemented!() + } + + fn clock_res_get(&self, id: types::Clockid) -> Result { + unimplemented!() + } + + fn clock_time_get( + &self, + id: types::Clockid, + _precision: types::Timestamp, + ) -> Result { + unimplemented!() + } + + fn fd_advise( + &self, + fd: types::Fd, + offset: types::Filesize, + len: types::Filesize, + advice: types::Advice, + ) -> Result<(), Error> { + let table = self.table(); + let file_entry: RefMut = table.get(u32::from(fd))?; + let f = file_entry.get_cap(FileCaps::ADVISE)?; + f.advise(offset, len, advice.into())?; + Ok(()) + } + + fn fd_allocate( + &self, + fd: types::Fd, + offset: types::Filesize, + len: types::Filesize, + ) -> Result<(), Error> { + unimplemented!() + } + + fn fd_close(&self, fd: types::Fd) -> Result<(), Error> { + unimplemented!() + } + + fn fd_datasync(&self, fd: types::Fd) -> Result<(), Error> { + unimplemented!() + } + + fn fd_fdstat_get(&self, fd: types::Fd) -> Result { + unimplemented!() + } + + fn fd_fdstat_set_flags(&self, fd: types::Fd, flags: types::Fdflags) -> Result<(), Error> { + unimplemented!() + } + + fn fd_fdstat_set_rights( + &self, + fd: types::Fd, + fs_rights_base: types::Rights, + fs_rights_inheriting: types::Rights, + ) -> Result<(), Error> { + unimplemented!() + } + + fn fd_filestat_get(&self, fd: types::Fd) -> Result { + unimplemented!() + } + + fn fd_filestat_set_size(&self, fd: types::Fd, size: types::Filesize) -> Result<(), Error> { + unimplemented!() + } + + fn fd_filestat_set_times( + &self, + fd: types::Fd, + atim: types::Timestamp, + mtim: types::Timestamp, + fst_flags: types::Fstflags, + ) -> Result<(), Error> { + unimplemented!() + } + + fn fd_read(&self, fd: types::Fd, iovs: &types::IovecArray<'_>) -> Result { + unimplemented!() + } + + fn fd_pread( + &self, + fd: types::Fd, + iovs: &types::IovecArray<'_>, + offset: types::Filesize, + ) -> Result { + unimplemented!() + } + + fn fd_write( + &self, + fd: types::Fd, + ciovs: &types::CiovecArray<'_>, + ) -> Result { + unimplemented!() + } + + fn fd_pwrite( + &self, + fd: types::Fd, + ciovs: &types::CiovecArray<'_>, + offset: types::Filesize, + ) -> Result { + unimplemented!() + } + + fn fd_prestat_get(&self, fd: types::Fd) -> Result { + unimplemented!() + } + + fn fd_prestat_dir_name( + &self, + fd: types::Fd, + path: &GuestPtr, + path_len: types::Size, + ) -> Result<(), Error> { + unimplemented!() + } + + fn fd_readdir( + &self, + fd: types::Fd, + buf: &GuestPtr, + buf_len: types::Size, + cookie: types::Dircookie, + ) -> Result { + unimplemented!() + } + + fn fd_renumber(&self, from: types::Fd, to: types::Fd) -> Result<(), Error> { + unimplemented!() + } + + fn fd_seek( + &self, + fd: types::Fd, + offset: types::Filedelta, + whence: types::Whence, + ) -> Result { + unimplemented!() + } + + fn fd_sync(&self, fd: types::Fd) -> Result<(), Error> { + unimplemented!() + } + + fn fd_tell(&self, fd: types::Fd) -> Result { + unimplemented!() + } + + fn path_create_directory( + &self, + dirfd: types::Fd, + path: &GuestPtr<'_, str>, + ) -> Result<(), Error> { + unimplemented!() + } + + fn path_filestat_get( + &self, + dirfd: types::Fd, + flags: types::Lookupflags, + path: &GuestPtr<'_, str>, + ) -> Result { + unimplemented!() + } + + fn path_filestat_set_times( + &self, + dirfd: types::Fd, + flags: types::Lookupflags, + path: &GuestPtr<'_, str>, + atim: types::Timestamp, + mtim: types::Timestamp, + fst_flags: types::Fstflags, + ) -> Result<(), Error> { + unimplemented!() + } + + fn path_link( + &self, + old_fd: types::Fd, + old_flags: types::Lookupflags, + old_path: &GuestPtr<'_, str>, + new_fd: types::Fd, + new_path: &GuestPtr<'_, str>, + ) -> Result<(), Error> { + unimplemented!() + } + + fn path_open( + &self, + dirfd: types::Fd, + dirflags: types::Lookupflags, + path: &GuestPtr<'_, str>, + oflags: types::Oflags, + fs_rights_base: types::Rights, + fs_rights_inheriting: types::Rights, + fdflags: types::Fdflags, + ) -> Result { + unimplemented!() + } + + fn path_readlink( + &self, + dirfd: types::Fd, + path: &GuestPtr<'_, str>, + buf: &GuestPtr, + buf_len: types::Size, + ) -> Result { + unimplemented!() + } + + fn path_remove_directory( + &self, + dirfd: types::Fd, + path: &GuestPtr<'_, str>, + ) -> Result<(), Error> { + unimplemented!() + } + + fn path_rename( + &self, + old_fd: types::Fd, + old_path: &GuestPtr<'_, str>, + new_fd: types::Fd, + new_path: &GuestPtr<'_, str>, + ) -> Result<(), Error> { + unimplemented!() + } + + fn path_symlink( + &self, + old_path: &GuestPtr<'_, str>, + dirfd: types::Fd, + new_path: &GuestPtr<'_, str>, + ) -> Result<(), Error> { + unimplemented!() + } + + fn path_unlink_file(&self, dirfd: types::Fd, path: &GuestPtr<'_, str>) -> Result<(), Error> { + unimplemented!() + } + + fn poll_oneoff( + &self, + subs: &GuestPtr, + events: &GuestPtr, + nsubscriptions: types::Size, + ) -> Result { + unimplemented!() + } + + fn proc_exit(&self, _rval: types::Exitcode) -> Result<(), ()> { + unimplemented!() + } + + fn proc_raise(&self, _sig: types::Signal) -> Result<(), Error> { + unimplemented!() + } + + fn sched_yield(&self) -> Result<(), Error> { + unimplemented!() + } + + fn random_get(&self, buf: &GuestPtr, buf_len: types::Size) -> Result<(), Error> { + unimplemented!() + } + + fn sock_recv( + &self, + _fd: types::Fd, + _ri_data: &types::IovecArray<'_>, + _ri_flags: types::Riflags, + ) -> Result<(types::Size, types::Roflags), Error> { + unimplemented!() + } + + fn sock_send( + &self, + _fd: types::Fd, + _si_data: &types::CiovecArray<'_>, + _si_flags: types::Siflags, + ) -> Result { + unimplemented!() + } + + fn sock_shutdown(&self, _fd: types::Fd, _how: types::Sdflags) -> Result<(), Error> { + unimplemented!() + } +} + +impl From for system_interface::fs::Advice { + fn from(advice: types::Advice) -> system_interface::fs::Advice { + match advice { + types::Advice::Normal => system_interface::fs::Advice::Normal, + types::Advice::Sequential => system_interface::fs::Advice::Sequential, + types::Advice::Random => system_interface::fs::Advice::Random, + types::Advice::Willneed => system_interface::fs::Advice::WillNeed, + types::Advice::Dontneed => system_interface::fs::Advice::DontNeed, + types::Advice::Noreuse => system_interface::fs::Advice::NoReuse, + } + } +} diff --git a/crates/wasi-c2/src/table.rs b/crates/wasi-c2/src/table.rs new file mode 100644 index 0000000000..f68747ba0b --- /dev/null +++ b/crates/wasi-c2/src/table.rs @@ -0,0 +1,46 @@ +use crate::Error; +use std::any::Any; +use std::cell::{RefCell, RefMut}; +use std::collections::HashMap; + +pub struct Table { + map: HashMap>>, + next_key: u32, +} + +impl Table { + pub fn new() -> Self { + Table { + map: HashMap::new(), + next_key: 0, + } + } + + pub fn insert(&mut self, a: impl Any + Sized) -> u32 { + let key = self.next_key; + self.next_key += 1; + self.map.insert(key, RefCell::new(Box::new(a))); + key + } + + // Todo: we can refine these errors and translate them to Exist at abi + pub fn get(&self, key: u32) -> Result, Error> { + if let Some(refcell) = self.map.get(&key) { + if let Ok(refmut) = refcell.try_borrow_mut() { + if refmut.is::() { + Ok(RefMut::map(refmut, |r| r.downcast_mut::().unwrap())) + } else { + Err(Error::Exist) // Exists at another type + } + } else { + Err(Error::Exist) // Does exist, but borrowed + } + } else { + Err(Error::Exist) // Does not exist + } + } + + pub fn delete(&mut self, key: u32) -> Option> { + self.map.remove(&key).map(|rc| RefCell::into_inner(rc)) + } +}