diff --git a/Cargo.lock b/Cargo.lock index 81b69a03056d..c012caff304d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3383,11 +3383,13 @@ dependencies = [ "getrandom", "libc", "sha2", + "tokio", "url", "wasi 0.11.0+wasi-snapshot-preview1", "wasi 0.14.0+wasi-0.2.3", "wasi-nn", "wit-bindgen", + "wit-bindgen-rt", ] [[package]] diff --git a/ci/vendor-wit.sh b/ci/vendor-wit.sh index 252fb9a863e5..7c6db6e95551 100755 --- a/ci/vendor-wit.sh +++ b/ci/vendor-wit.sh @@ -19,24 +19,24 @@ make_vendor() { mkdir -p $path for package in $packages; do - IFS='@' read -r repo tag <<< "$package" - mkdir -p $path/$repo + IFS='@' read -r repo tag subdir <<< "$package" + mkdir -p "$path/$package" cached_extracted_dir="$cache_dir/$repo-$tag" if [[ ! -d $cached_extracted_dir ]]; then mkdir -p $cached_extracted_dir curl -sL https://github.com/WebAssembly/wasi-$repo/archive/$tag.tar.gz | \ tar xzf - --strip-components=1 -C $cached_extracted_dir - rm -rf $cached_extracted_dir/wit/deps* + rm -rf $cached_extracted_dir/${subdir:-"wit"}/deps* fi - cp -r $cached_extracted_dir/wit/* $path/$repo + cp -r $cached_extracted_dir/${subdir:-"wit"}/* $path/$package done } cache_dir=$(mktemp -d) -make_vendor "wasi" " +make_vendor "wasi/src/p2" " cli@v0.2.3 clocks@v0.2.3 filesystem@v0.2.3 @@ -45,7 +45,12 @@ make_vendor "wasi" " sockets@v0.2.3 " -make_vendor "wasi-http" " +make_vendor "wasi/src/p3" " + clocks@3850f9d@wit-0.3.0-draft + random@3e99124@wit-0.3.0-draft +" + +make_vendor "wasi-http/src/p2" " cli@v0.2.3 clocks@v0.2.3 filesystem@v0.2.3 @@ -55,9 +60,9 @@ make_vendor "wasi-http" " http@v0.2.3 " -make_vendor "wasi-config" "config@f4d699b" +make_vendor "wasi-config/src/p2" "config@f4d699b" -make_vendor "wasi-keyvalue" "keyvalue@219ea36" +make_vendor "wasi-keyvalue/src/p2" "keyvalue@219ea36" rm -rf $cache_dir diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml index ec734b766b03..ee75288c79ae 100644 --- a/crates/test-programs/Cargo.toml +++ b/crates/test-programs/Cargo.toml @@ -15,6 +15,8 @@ anyhow = { workspace = true, features = ['std'] } wasi = "0.11.0" wasi-nn = "0.6.0" wit-bindgen = { workspace = true, features = ['default'] } +# TODO: Remove once https://github.com/bytecodealliance/wit-bindgen/pull/1136 lands +wit-bindgen-rt = "0.37" libc = { workspace = true } getrandom = "0.2.9" futures = { workspace = true, default-features = false, features = ['alloc'] } @@ -22,3 +24,4 @@ url = { workspace = true } sha2 = "0.10.2" base64 = "0.21.0" wasip2 = { version = "0.14.0", package = 'wasi' } +tokio = { workspace = true, features = ["macros"] } diff --git a/crates/test-programs/artifacts/build.rs b/crates/test-programs/artifacts/build.rs index f5966a67ea5e..7b75ebb265cc 100644 --- a/crates/test-programs/artifacts/build.rs +++ b/crates/test-programs/artifacts/build.rs @@ -71,6 +71,7 @@ fn build_and_generate_tests() { s if s.starts_with("http_") => "http", s if s.starts_with("preview1_") => "preview1", s if s.starts_with("preview2_") => "preview2", + s if s.starts_with("preview3_") => "preview3", s if s.starts_with("cli_") => "cli", s if s.starts_with("api_") => "api", s if s.starts_with("nn_") => "nn", diff --git a/crates/test-programs/src/bin/api_reactor.rs b/crates/test-programs/src/bin/api_reactor.rs index 360c96fab61b..3f8b420b6e6b 100644 --- a/crates/test-programs/src/bin/api_reactor.rs +++ b/crates/test-programs/src/bin/api_reactor.rs @@ -2,7 +2,7 @@ use std::sync::{Mutex, MutexGuard}; wit_bindgen::generate!({ world: "test-reactor", - path: "../wasi/wit", + path: "../wasi/src/p2/wit", generate_all, }); diff --git a/crates/test-programs/src/bin/preview2_random.rs b/crates/test-programs/src/bin/preview2_random.rs index 491037d65794..be26b65ee610 100644 --- a/crates/test-programs/src/bin/preview2_random.rs +++ b/crates/test-programs/src/bin/preview2_random.rs @@ -1,4 +1,4 @@ -use test_programs::wasi::random; +use test_programs::wasi::random0_2_3 as random; fn main() { let mut bytes = [0_u8; 256]; diff --git a/crates/test-programs/src/bin/preview2_sleep.rs b/crates/test-programs/src/bin/preview2_sleep.rs index a6c8dae39840..a3ea8ec5f8f2 100644 --- a/crates/test-programs/src/bin/preview2_sleep.rs +++ b/crates/test-programs/src/bin/preview2_sleep.rs @@ -1,4 +1,4 @@ -use test_programs::wasi::clocks::monotonic_clock; +use test_programs::wasi::clocks0_2_3::monotonic_clock; fn main() { sleep_10ms(); diff --git a/crates/test-programs/src/bin/preview3_random.rs b/crates/test-programs/src/bin/preview3_random.rs new file mode 100644 index 000000000000..4f363c10405d --- /dev/null +++ b/crates/test-programs/src/bin/preview3_random.rs @@ -0,0 +1,40 @@ +use test_programs::wasi::random0_3_0 as random; + +fn main() { + let mut bytes = [0_u8; 256]; + getrandom::getrandom(&mut bytes).unwrap(); + + assert!(bytes.iter().any(|x| *x != 0)); + + // Acquired random bytes should be of the expected length. + let array = random::random::get_random_bytes(100); + assert_eq!(array.len(), 100); + + // It shouldn't take 100+ tries to get a nonzero random integer. + for i in 0.. { + if random::random::get_random_u64() == 0 { + continue; + } + assert!(i < 100); + break; + } + + // The `insecure_seed` API should return the same result each time. + let (a1, b1) = random::insecure_seed::insecure_seed(); + let (a2, b2) = random::insecure_seed::insecure_seed(); + assert_eq!(a1, a2); + assert_eq!(b1, b2); + + // Acquired random bytes should be of the expected length. + let array = random::insecure::get_insecure_random_bytes(100); + assert_eq!(array.len(), 100); + + // It shouldn't take 100+ tries to get a nonzero random integer. + for i in 0.. { + if random::insecure::get_insecure_random_u64() == 0 { + continue; + } + assert!(i < 100); + break; + } +} diff --git a/crates/test-programs/src/bin/preview3_sleep.rs b/crates/test-programs/src/bin/preview3_sleep.rs new file mode 100644 index 000000000000..b205b2e530b8 --- /dev/null +++ b/crates/test-programs/src/bin/preview3_sleep.rs @@ -0,0 +1,62 @@ +use core::future::Future as _; +use core::pin::pin; +use core::ptr; +use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; + +use test_programs::wasi::clocks0_3_0::monotonic_clock; + +// Adapted from https://github.com/rust-lang/rust/blob/cd805f09ffbfa3896c8f50a619de9b67e1d9f3c3/library/core/src/task/wake.rs#L63-L77 +// TODO: Replace by `Waker::noop` once MSRV is raised to 1.85 +const NOOP_RAW_WAKER: RawWaker = { + const VTABLE: RawWakerVTable = RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| NOOP_RAW_WAKER, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + RawWaker::new(ptr::null(), &VTABLE) +}; + +const NOOP_WAKER: &'static Waker = &unsafe { Waker::from_raw(NOOP_RAW_WAKER) }; + +#[tokio::main(flavor = "current_thread")] +async fn main() { + sleep_10ms().await; + sleep_0ms(); + sleep_backwards_in_time(); +} + +async fn sleep_10ms() { + let dur = 10_000_000; + monotonic_clock::wait_until(monotonic_clock::now() + dur).await; + monotonic_clock::wait_for(dur).await; +} + +fn sleep_0ms() { + let mut cx = Context::from_waker(NOOP_WAKER); + + assert_eq!( + pin!(monotonic_clock::wait_until(monotonic_clock::now())).poll(&mut cx), + Poll::Ready(()), + "waiting until now() is ready immediately", + ); + assert_eq!( + pin!(monotonic_clock::wait_for(0)).poll(&mut cx), + Poll::Ready(()), + "waiting for 0 is ready immediately", + ); +} + +fn sleep_backwards_in_time() { + let mut cx = Context::from_waker(NOOP_WAKER); + + assert_eq!( + pin!(monotonic_clock::wait_until(monotonic_clock::now() - 1)).poll(&mut cx), + Poll::Ready(()), + "waiting until instant which has passed is ready immediately", + ); +} diff --git a/crates/test-programs/src/lib.rs b/crates/test-programs/src/lib.rs index 49301621dbd0..f86e35c7a246 100644 --- a/crates/test-programs/src/lib.rs +++ b/crates/test-programs/src/lib.rs @@ -12,36 +12,46 @@ wit_bindgen::generate!({ include wasi:http/imports@0.2.3; include wasi:config/imports@0.2.0-draft; include wasi:keyvalue/imports@0.2.0-draft; + + include wasi:clocks/imports@0.3.0; + include wasi:random/imports@0.3.0; } ", path: [ - "../wasi-http/wit", - "../wasi-config/wit", - "../wasi-keyvalue/wit", + "../wasi/src/p3/wit", + "../wasi-http/src/p2/wit", + "../wasi-config/src/p2/wit", + "../wasi-keyvalue/src/p2/wit", ], world: "wasmtime:test/test", features: ["cli-exit-with-code"], + async: { + imports: [ + "wasi:clocks/monotonic-clock@0.3.0#wait-for", + "wasi:clocks/monotonic-clock@0.3.0#wait-until", + ], + }, generate_all, }); pub mod proxy { wit_bindgen::generate!({ - path: "../wasi-http/wit", + path: "../wasi-http/src/p2/wit", world: "wasi:http/proxy", default_bindings_module: "test_programs::proxy", pub_export_macro: true, with: { "wasi:http/types@0.2.3": crate::wasi::http::types, "wasi:http/outgoing-handler@0.2.3": crate::wasi::http::outgoing_handler, - "wasi:random/random@0.2.3": crate::wasi::random::random, + "wasi:random/random@0.2.3": crate::wasi::random0_2_3::random, "wasi:io/error@0.2.3": crate::wasi::io::error, "wasi:io/poll@0.2.3": crate::wasi::io::poll, "wasi:io/streams@0.2.3": crate::wasi::io::streams, "wasi:cli/stdout@0.2.3": crate::wasi::cli::stdout, "wasi:cli/stderr@0.2.3": crate::wasi::cli::stderr, "wasi:cli/stdin@0.2.3": crate::wasi::cli::stdin, - "wasi:clocks/monotonic-clock@0.2.3": crate::wasi::clocks::monotonic_clock, - "wasi:clocks/wall-clock@0.2.3": crate::wasi::clocks::wall_clock, + "wasi:clocks/monotonic-clock@0.2.3": crate::wasi::clocks0_2_3::monotonic_clock, + "wasi:clocks/wall-clock@0.2.3": crate::wasi::clocks0_2_3::wall_clock, }, }); } diff --git a/crates/test-programs/src/sockets.rs b/crates/test-programs/src/sockets.rs index 0fcccaaab4af..0c41031a10fc 100644 --- a/crates/test-programs/src/sockets.rs +++ b/crates/test-programs/src/sockets.rs @@ -1,7 +1,7 @@ -use crate::wasi::clocks::monotonic_clock; +use crate::wasi::clocks0_2_3::monotonic_clock; use crate::wasi::io::poll::{self, Pollable}; use crate::wasi::io::streams::{InputStream, OutputStream, StreamError}; -use crate::wasi::random; +use crate::wasi::random0_2_3 as random; use crate::wasi::sockets::instance_network; use crate::wasi::sockets::ip_name_lookup; use crate::wasi::sockets::network::{ diff --git a/crates/wasi-config/src/lib.rs b/crates/wasi-config/src/lib.rs index ec6f3bd595b0..ffee81248225 100644 --- a/crates/wasi-config/src/lib.rs +++ b/crates/wasi-config/src/lib.rs @@ -67,17 +67,11 @@ #![deny(missing_docs)] -use anyhow::Result; use std::collections::HashMap; -mod gen_ { - wasmtime::component::bindgen!({ - path: "wit", - world: "wasi:config/imports", - trappable_imports: true, - }); -} -use self::gen_::wasi::config::store as generated; +pub mod p2; +#[doc(inline)] +pub use p2::*; /// Capture the state necessary for use in the `wasi-config` API implementation. #[derive(Default)] @@ -123,27 +117,3 @@ impl<'a> WasiConfig<'a> { Self { vars } } } - -impl generated::Host for WasiConfig<'_> { - fn get(&mut self, key: String) -> Result, generated::Error>> { - Ok(Ok(self.vars.0.get(&key).map(|s| s.to_owned()))) - } - - fn get_all(&mut self) -> Result, generated::Error>> { - Ok(Ok(self - .vars - .0 - .iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .collect())) - } -} - -/// Add all the `wasi-config` world's interfaces to a [`wasmtime::component::Linker`]. -pub fn add_to_linker( - l: &mut wasmtime::component::Linker, - f: impl Fn(&mut T) -> WasiConfig<'_> + Send + Sync + Copy + 'static, -) -> Result<()> { - generated::add_to_linker_get_host(l, f)?; - Ok(()) -} diff --git a/crates/wasi-config/src/p2/mod.rs b/crates/wasi-config/src/p2/mod.rs new file mode 100644 index 000000000000..4d2bfb38f41a --- /dev/null +++ b/crates/wasi-config/src/p2/mod.rs @@ -0,0 +1,36 @@ +//! Implementation of wasip2 version of `wasi:config` package + +mod gen_ { + wasmtime::component::bindgen!({ + path: "src/p2/wit", + world: "wasi:config/imports", + trappable_imports: true, + }); +} +use self::gen_::wasi::config::store as generated; + +use crate::WasiConfig; + +impl generated::Host for WasiConfig<'_> { + fn get(&mut self, key: String) -> anyhow::Result, generated::Error>> { + Ok(Ok(self.vars.0.get(&key).map(|s| s.to_owned()))) + } + + fn get_all(&mut self) -> anyhow::Result, generated::Error>> { + Ok(Ok(self + .vars + .0 + .iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect())) + } +} + +/// Add all the `wasi-config` world's interfaces to a [`wasmtime::component::Linker`]. +pub fn add_to_linker( + l: &mut wasmtime::component::Linker, + f: impl Fn(&mut T) -> WasiConfig<'_> + Send + Sync + Copy + 'static, +) -> anyhow::Result<()> { + generated::add_to_linker_get_host(l, f)?; + Ok(()) +} diff --git a/crates/wasi-config/wit/deps/config/store.wit b/crates/wasi-config/src/p2/wit/deps/config@f4d699b/store.wit similarity index 100% rename from crates/wasi-config/wit/deps/config/store.wit rename to crates/wasi-config/src/p2/wit/deps/config@f4d699b/store.wit diff --git a/crates/wasi-config/wit/deps/config/world.wit b/crates/wasi-config/src/p2/wit/deps/config@f4d699b/world.wit similarity index 100% rename from crates/wasi-config/wit/deps/config/world.wit rename to crates/wasi-config/src/p2/wit/deps/config@f4d699b/world.wit diff --git a/crates/wasi-config/wit/world.wit b/crates/wasi-config/src/p2/wit/world.wit similarity index 100% rename from crates/wasi-config/wit/world.wit rename to crates/wasi-config/src/p2/wit/world.wit diff --git a/crates/wasi-http/src/body.rs b/crates/wasi-http/src/body.rs index 96c783964746..285e6b1cca02 100644 --- a/crates/wasi-http/src/body.rs +++ b/crates/wasi-http/src/body.rs @@ -1,6 +1,6 @@ //! Implementation of the `wasi:http/types` interface's various body types. -use crate::{bindings::http::types, types::FieldMap}; +use crate::{p2::bindings::http::types, types::FieldMap}; use anyhow::anyhow; use bytes::Bytes; use http_body::{Body, Frame}; diff --git a/crates/wasi-http/src/error.rs b/crates/wasi-http/src/error.rs index 1c60a4b0771e..e65c147656bd 100644 --- a/crates/wasi-http/src/error.rs +++ b/crates/wasi-http/src/error.rs @@ -1,4 +1,4 @@ -use crate::bindings::http::types::ErrorCode; +use crate::p2::bindings::http::types::ErrorCode; use std::error::Error; use std::fmt; use wasmtime_wasi::ResourceTableError; @@ -59,7 +59,7 @@ impl fmt::Display for HttpError { impl Error for HttpError {} pub(crate) fn dns_error(rcode: String, info_code: u16) -> ErrorCode { - ErrorCode::DnsError(crate::bindings::http::types::DnsErrorPayload { + ErrorCode::DnsError(crate::p2::bindings::http::types::DnsErrorPayload { rcode: Some(rcode), info_code: Some(info_code), }) diff --git a/crates/wasi-http/src/lib.rs b/crates/wasi-http/src/lib.rs index 9c57a6b6a974..b579e0dba024 100644 --- a/crates/wasi-http/src/lib.rs +++ b/crates/wasi-http/src/lib.rs @@ -1,28 +1,9 @@ //! # Wasmtime's WASI HTTP Implementation //! -//! This crate is Wasmtime's host implementation of the `wasi:http` package as -//! part of WASIp2. This crate's implementation is primarily built on top of +//! This crate is Wasmtime's host implementation of the `wasi:http` package. +//! This crate's implementation is primarily built on top of //! [`hyper`] and [`tokio`]. //! -//! # WASI HTTP Interfaces -//! -//! This crate contains implementations of the following interfaces: -//! -//! * [`wasi:http/incoming-handler`] -//! * [`wasi:http/outgoing-handler`] -//! * [`wasi:http/types`] -//! -//! The crate also contains an implementation of the [`wasi:http/proxy`] world. -//! -//! [`wasi:http/proxy`]: crate::bindings::Proxy -//! [`wasi:http/outgoing-handler`]: crate::bindings::http::outgoing_handler::Host -//! [`wasi:http/types`]: crate::bindings::http::types::Host -//! [`wasi:http/incoming-handler`]: crate::bindings::exports::wasi::http::incoming_handler::Guest -//! -//! This crate is very similar to [`wasmtime-wasi`] in the it uses the -//! `bindgen!` macro in Wasmtime to generate bindings to interfaces. Bindings -//! are located in the [`bindings`] module. -//! //! # The `WasiHttpView` trait //! //! All `bindgen!`-generated `Host` traits are implemented in terms of a @@ -55,7 +36,7 @@ //! no others. This is useful when working with //! [`wasmtime_wasi::add_to_linker_async`] for example. //! * Add individual interfaces such as with the -//! [`bindings::http::outgoing_handler::add_to_linker_get_host`] function. +//! [`p2::bindings::http::outgoing_handler::add_to_linker_get_host`] function. //! 3. Use [`ProxyPre`](bindings::ProxyPre) to pre-instantiate a component //! before serving requests. //! 4. When serving requests use @@ -217,15 +198,12 @@ #![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] mod error; -mod http_impl; -mod types_impl; pub mod body; pub mod io; +pub mod p2; pub mod types; -pub mod bindings; - pub use crate::error::{ http_request_error, hyper_request_error, hyper_response_error, HttpError, HttpResult, }; @@ -234,70 +212,8 @@ pub use crate::types::{ WasiHttpCtx, WasiHttpImpl, WasiHttpView, DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS, DEFAULT_OUTGOING_BODY_CHUNK_SIZE, }; -use wasmtime_wasi::IoImpl; -/// Add all of the `wasi:http/proxy` world's interfaces to a [`wasmtime::component::Linker`]. -/// -/// This function will add the `async` variant of all interfaces into the -/// `Linker` provided. By `async` this means that this function is only -/// compatible with [`Config::async_support(true)`][async]. For embeddings with -/// async support disabled see [`add_to_linker_sync`] instead. -/// -/// [async]: wasmtime::Config::async_support -/// -/// # Example -/// -/// ``` -/// use wasmtime::{Engine, Result, Config}; -/// use wasmtime::component::{ResourceTable, Linker}; -/// use wasmtime_wasi::{IoView, WasiCtx, WasiView}; -/// use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView}; -/// -/// fn main() -> Result<()> { -/// let mut config = Config::new(); -/// config.async_support(true); -/// let engine = Engine::new(&config)?; -/// -/// let mut linker = Linker::::new(&engine); -/// wasmtime_wasi_http::add_to_linker_async(&mut linker)?; -/// // ... add any further functionality to `linker` if desired ... -/// -/// Ok(()) -/// } -/// -/// struct MyState { -/// ctx: WasiCtx, -/// http_ctx: WasiHttpCtx, -/// table: ResourceTable, -/// } -/// -/// impl IoView for MyState { -/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } -/// } -/// impl WasiHttpView for MyState { -/// fn ctx(&mut self) -> &mut WasiHttpCtx { &mut self.http_ctx } -/// } -/// impl WasiView for MyState { -/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } -/// } -/// ``` -pub fn add_to_linker_async(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> -where - T: WasiHttpView + wasmtime_wasi::WasiView, -{ - let io_closure = type_annotate_io::(|t| wasmtime_wasi::IoImpl(t)); - let closure = type_annotate_wasi::(|t| wasmtime_wasi::WasiImpl(wasmtime_wasi::IoImpl(t))); - wasmtime_wasi::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::io::poll::add_to_linker_get_host(l, io_closure)?; - wasmtime_wasi::bindings::io::error::add_to_linker_get_host(l, io_closure)?; - wasmtime_wasi::bindings::io::streams::add_to_linker_get_host(l, io_closure)?; - wasmtime_wasi::bindings::cli::stdin::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::cli::stdout::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::cli::stderr::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::random::random::add_to_linker_get_host(l, closure)?; - - add_only_http_to_linker_async(l) -} +#[doc(inline)] +pub use p2::*; // NB: workaround some rustc inference - a future refactoring may make this // obsolete. @@ -319,100 +235,3 @@ where { val } - -/// A slimmed down version of [`add_to_linker_async`] which only adds -/// `wasi:http` interfaces to the linker. -/// -/// This is useful when using [`wasmtime_wasi::add_to_linker_async`] for -/// example to avoid re-adding the same interfaces twice. -pub fn add_only_http_to_linker_async( - l: &mut wasmtime::component::Linker, -) -> anyhow::Result<()> -where - T: WasiHttpView, -{ - let closure = type_annotate_http::(|t| WasiHttpImpl(IoImpl(t))); - crate::bindings::http::outgoing_handler::add_to_linker_get_host(l, closure)?; - crate::bindings::http::types::add_to_linker_get_host(l, closure)?; - - Ok(()) -} - -/// Add all of the `wasi:http/proxy` world's interfaces to a [`wasmtime::component::Linker`]. -/// -/// This function will add the `sync` variant of all interfaces into the -/// `Linker` provided. For embeddings with async support see -/// [`add_to_linker_async`] instead. -/// -/// # Example -/// -/// ``` -/// use wasmtime::{Engine, Result, Config}; -/// use wasmtime::component::{ResourceTable, Linker}; -/// use wasmtime_wasi::{IoView, WasiCtx, WasiView}; -/// use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView}; -/// -/// fn main() -> Result<()> { -/// let config = Config::default(); -/// let engine = Engine::new(&config)?; -/// -/// let mut linker = Linker::::new(&engine); -/// wasmtime_wasi_http::add_to_linker_sync(&mut linker)?; -/// // ... add any further functionality to `linker` if desired ... -/// -/// Ok(()) -/// } -/// -/// struct MyState { -/// ctx: WasiCtx, -/// http_ctx: WasiHttpCtx, -/// table: ResourceTable, -/// } -/// impl IoView for MyState { -/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } -/// } -/// impl WasiHttpView for MyState { -/// fn ctx(&mut self) -> &mut WasiHttpCtx { &mut self.http_ctx } -/// } -/// impl WasiView for MyState { -/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } -/// } -/// ``` -pub fn add_to_linker_sync(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> -where - T: WasiHttpView + wasmtime_wasi::WasiView, -{ - let io_closure = type_annotate_io::(|t| wasmtime_wasi::IoImpl(t)); - let closure = type_annotate_wasi::(|t| wasmtime_wasi::WasiImpl(wasmtime_wasi::IoImpl(t))); - - wasmtime_wasi::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::sync::io::poll::add_to_linker_get_host(l, io_closure)?; - wasmtime_wasi::bindings::sync::io::streams::add_to_linker_get_host(l, io_closure)?; - wasmtime_wasi::bindings::io::error::add_to_linker_get_host(l, io_closure)?; - wasmtime_wasi::bindings::cli::stdin::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::cli::stdout::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::cli::stderr::add_to_linker_get_host(l, closure)?; - wasmtime_wasi::bindings::random::random::add_to_linker_get_host(l, closure)?; - - add_only_http_to_linker_sync(l)?; - - Ok(()) -} - -/// A slimmed down version of [`add_to_linker_sync`] which only adds -/// `wasi:http` interfaces to the linker. -/// -/// This is useful when using [`wasmtime_wasi::add_to_linker_sync`] for -/// example to avoid re-adding the same interfaces twice. -pub fn add_only_http_to_linker_sync(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> -where - T: WasiHttpView, -{ - let closure = type_annotate_http::(|t| WasiHttpImpl(IoImpl(t))); - - crate::bindings::http::outgoing_handler::add_to_linker_get_host(l, closure)?; - crate::bindings::http::types::add_to_linker_get_host(l, closure)?; - - Ok(()) -} diff --git a/crates/wasi-http/src/bindings.rs b/crates/wasi-http/src/p2/bindings.rs similarity index 88% rename from crates/wasi-http/src/bindings.rs rename to crates/wasi-http/src/p2/bindings.rs index 00054e5a644b..0974ced42547 100644 --- a/crates/wasi-http/src/bindings.rs +++ b/crates/wasi-http/src/p2/bindings.rs @@ -6,7 +6,7 @@ mod generated { use crate::types; wasmtime::component::bindgen!({ - path: "wit", + path: "src/p2/wit", world: "wasi:http/proxy", tracing: true, // Flag this as "possibly async" which will cause the exports to be @@ -19,7 +19,7 @@ mod generated { require_store_data_send: true, with: { // Upstream package dependencies - "wasi:io": wasmtime_wasi::bindings::io, + "wasi:io": wasmtime_wasi::p2::bindings::io, // Configure all WIT http resources to be defined types in this // crate to use the `ResourceTable` helper methods. @@ -55,13 +55,14 @@ pub mod sync { mod generated { #![allow(missing_docs)] wasmtime::component::bindgen!({ + path: "src/p2/wit", world: "wasi:http/proxy", tracing: true, async: false, with: { - "wasi:http": crate::bindings::http, // http is in this crate - "wasi:io": wasmtime_wasi::bindings::sync::io, // io is sync - "wasi": wasmtime_wasi::bindings, // everything else + "wasi:http": crate::p2::bindings::http, // http is in this crate + "wasi:io": wasmtime_wasi::p2::bindings::sync::io, // io is sync + "wasi": wasmtime_wasi::p2::bindings, // everything else }, require_store_data_send: true, }); diff --git a/crates/wasi-http/src/http_impl.rs b/crates/wasi-http/src/p2/http_impl.rs similarity index 99% rename from crates/wasi-http/src/http_impl.rs rename to crates/wasi-http/src/p2/http_impl.rs index 8850b63f29c6..3f8746041f8f 100644 --- a/crates/wasi-http/src/http_impl.rs +++ b/crates/wasi-http/src/p2/http_impl.rs @@ -1,12 +1,12 @@ //! Implementation of the `wasi:http/outgoing-handler` interface. use crate::{ - bindings::http::{ + error::internal_error, + http_request_error, + p2::bindings::http::{ outgoing_handler, types::{self, Scheme}, }, - error::internal_error, - http_request_error, types::{HostFutureIncomingResponse, HostOutgoingRequest, OutgoingRequestConfig}, WasiHttpImpl, WasiHttpView, }; diff --git a/crates/wasi-http/src/p2/mod.rs b/crates/wasi-http/src/p2/mod.rs new file mode 100644 index 000000000000..159b01ab3a14 --- /dev/null +++ b/crates/wasi-http/src/p2/mod.rs @@ -0,0 +1,189 @@ +//! Implementation of wasip2 version of `wasi:http` package +//! +//! # WASI HTTP Interfaces +//! +//! This module contains implementations of the following interfaces: +//! +//! * [`wasi:http/incoming-handler`] +//! * [`wasi:http/outgoing-handler`] +//! * [`wasi:http/types`] +//! +//! The module also contains an implementation of the [`wasi:http/proxy`] world. +//! +//! [`wasi:http/proxy`]: crate::p2::bindings::Proxy +//! [`wasi:http/outgoing-handler`]: crate::p2::bindings::http::outgoing_handler::Host +//! [`wasi:http/types`]: crate::p2::bindings::http::types::Host +//! [`wasi:http/incoming-handler`]: crate::p2::bindings::exports::wasi::http::incoming_handler::Guest +//! +//! This module is very similar to [`wasmtime-wasi`] in the it uses the +//! `bindgen!` macro in Wasmtime to generate bindings to interfaces. Bindings +//! are located in the [`bindings`] submodule. + +mod http_impl; +mod types_impl; + +pub mod bindings; + +use crate::types::{WasiHttpImpl, WasiHttpView}; +use crate::{type_annotate_http, type_annotate_io, type_annotate_wasi}; +use wasmtime_wasi::IoImpl; +/// Add all of the `wasi:http/proxy` world's interfaces to a [`wasmtime::component::Linker`]. +/// +/// This function will add the `async` variant of all interfaces into the +/// `Linker` provided. By `async` this means that this function is only +/// compatible with [`Config::async_support(true)`][async]. For embeddings with +/// async support disabled see [`add_to_linker_sync`] instead. +/// +/// [async]: wasmtime::Config::async_support +/// +/// # Example +/// +/// ``` +/// use wasmtime::{Engine, Result, Config}; +/// use wasmtime::component::{ResourceTable, Linker}; +/// use wasmtime_wasi::{IoView, WasiCtx, WasiView}; +/// use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView}; +/// +/// fn main() -> Result<()> { +/// let mut config = Config::new(); +/// config.async_support(true); +/// let engine = Engine::new(&config)?; +/// +/// let mut linker = Linker::::new(&engine); +/// wasmtime_wasi_http::add_to_linker_async(&mut linker)?; +/// // ... add any further functionality to `linker` if desired ... +/// +/// Ok(()) +/// } +/// +/// struct MyState { +/// ctx: WasiCtx, +/// http_ctx: WasiHttpCtx, +/// table: ResourceTable, +/// } +/// +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiHttpView for MyState { +/// fn ctx(&mut self) -> &mut WasiHttpCtx { &mut self.http_ctx } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// ``` +pub fn add_to_linker_async(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> +where + T: WasiHttpView + wasmtime_wasi::WasiView, +{ + let io_closure = type_annotate_io::(|t| wasmtime_wasi::IoImpl(t)); + let closure = type_annotate_wasi::(|t| wasmtime_wasi::WasiImpl(wasmtime_wasi::IoImpl(t))); + wasmtime_wasi::p2::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::io::poll::add_to_linker_get_host(l, io_closure)?; + wasmtime_wasi::p2::bindings::io::error::add_to_linker_get_host(l, io_closure)?; + wasmtime_wasi::p2::bindings::io::streams::add_to_linker_get_host(l, io_closure)?; + wasmtime_wasi::p2::bindings::cli::stdin::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::cli::stdout::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::cli::stderr::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::random::random::add_to_linker_get_host(l, closure)?; + + add_only_http_to_linker_async(l) +} + +/// A slimmed down version of [`add_to_linker_async`] which only adds +/// `wasi:http` interfaces to the linker. +/// +/// This is useful when using [`wasmtime_wasi::add_to_linker_async`] for +/// example to avoid re-adding the same interfaces twice. +pub fn add_only_http_to_linker_async( + l: &mut wasmtime::component::Linker, +) -> anyhow::Result<()> +where + T: WasiHttpView, +{ + let closure = type_annotate_http::(|t| WasiHttpImpl(IoImpl(t))); + self::bindings::http::outgoing_handler::add_to_linker_get_host(l, closure)?; + self::bindings::http::types::add_to_linker_get_host(l, closure)?; + + Ok(()) +} + +/// Add all of the `wasi:http/proxy` world's interfaces to a [`wasmtime::component::Linker`]. +/// +/// This function will add the `sync` variant of all interfaces into the +/// `Linker` provided. For embeddings with async support see +/// [`add_to_linker_async`] instead. +/// +/// # Example +/// +/// ``` +/// use wasmtime::{Engine, Result, Config}; +/// use wasmtime::component::{ResourceTable, Linker}; +/// use wasmtime_wasi::{IoView, WasiCtx, WasiView}; +/// use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView}; +/// +/// fn main() -> Result<()> { +/// let config = Config::default(); +/// let engine = Engine::new(&config)?; +/// +/// let mut linker = Linker::::new(&engine); +/// wasmtime_wasi_http::add_to_linker_sync(&mut linker)?; +/// // ... add any further functionality to `linker` if desired ... +/// +/// Ok(()) +/// } +/// +/// struct MyState { +/// ctx: WasiCtx, +/// http_ctx: WasiHttpCtx, +/// table: ResourceTable, +/// } +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiHttpView for MyState { +/// fn ctx(&mut self) -> &mut WasiHttpCtx { &mut self.http_ctx } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// ``` +pub fn add_to_linker_sync(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> +where + T: WasiHttpView + wasmtime_wasi::WasiView, +{ + let io_closure = type_annotate_io::(|t| wasmtime_wasi::IoImpl(t)); + let closure = type_annotate_wasi::(|t| wasmtime_wasi::WasiImpl(wasmtime_wasi::IoImpl(t))); + + wasmtime_wasi::p2::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::sync::io::poll::add_to_linker_get_host(l, io_closure)?; + wasmtime_wasi::p2::bindings::sync::io::streams::add_to_linker_get_host(l, io_closure)?; + wasmtime_wasi::p2::bindings::io::error::add_to_linker_get_host(l, io_closure)?; + wasmtime_wasi::p2::bindings::cli::stdin::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::cli::stdout::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::cli::stderr::add_to_linker_get_host(l, closure)?; + wasmtime_wasi::p2::bindings::random::random::add_to_linker_get_host(l, closure)?; + + add_only_http_to_linker_sync(l)?; + + Ok(()) +} + +/// A slimmed down version of [`add_to_linker_sync`] which only adds +/// `wasi:http` interfaces to the linker. +/// +/// This is useful when using [`wasmtime_wasi::add_to_linker_sync`] for +/// example to avoid re-adding the same interfaces twice. +pub fn add_only_http_to_linker_sync(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> +where + T: WasiHttpView, +{ + let closure = type_annotate_http::(|t| WasiHttpImpl(IoImpl(t))); + + self::bindings::http::outgoing_handler::add_to_linker_get_host(l, closure)?; + self::bindings::http::types::add_to_linker_get_host(l, closure)?; + + Ok(()) +} diff --git a/crates/wasi-http/src/types_impl.rs b/crates/wasi-http/src/p2/types_impl.rs similarity index 96% rename from crates/wasi-http/src/types_impl.rs rename to crates/wasi-http/src/p2/types_impl.rs index f3a83f85d6d7..c83e0d6d0724 100644 --- a/crates/wasi-http/src/types_impl.rs +++ b/crates/wasi-http/src/p2/types_impl.rs @@ -1,8 +1,8 @@ //! Implementation for the `wasi:http/types` interface. use crate::{ - bindings::http::types::{self, Headers, Method, Scheme, StatusCode, Trailers}, body::{HostFutureTrailers, HostIncomingBody, HostOutgoingBody, StreamContext}, + p2::bindings::http::types::{self, Headers, Method, Scheme, StatusCode, Trailers}, types::{ is_forbidden_header, remove_forbidden_headers, FieldMap, HostFields, HostFutureIncomingResponse, HostIncomingRequest, HostIncomingResponse, HostOutgoingRequest, @@ -15,11 +15,11 @@ use std::any::Any; use std::str::FromStr; use wasmtime::component::{Resource, ResourceTable}; use wasmtime_wasi::{ - bindings::io::streams::{InputStream, OutputStream}, + p2::bindings::io::streams::{InputStream, OutputStream}, IoView, Pollable, ResourceTableError, }; -impl crate::bindings::http::types::Host for WasiHttpImpl +impl crate::p2::bindings::http::types::Host for WasiHttpImpl where T: WasiHttpView, { @@ -101,7 +101,7 @@ fn get_fields_mut<'a>( } } -impl crate::bindings::http::types::HostFields for WasiHttpImpl +impl crate::p2::bindings::http::types::HostFields for WasiHttpImpl where T: WasiHttpView, { @@ -291,7 +291,7 @@ where } } -impl crate::bindings::http::types::HostIncomingRequest for WasiHttpImpl +impl crate::p2::bindings::http::types::HostIncomingRequest for WasiHttpImpl where T: WasiHttpView, { @@ -365,7 +365,7 @@ where } } -impl crate::bindings::http::types::HostOutgoingRequest for WasiHttpImpl +impl crate::p2::bindings::http::types::HostOutgoingRequest for WasiHttpImpl where T: WasiHttpView, { @@ -557,7 +557,7 @@ where } } -impl crate::bindings::http::types::HostResponseOutparam for WasiHttpImpl +impl crate::p2::bindings::http::types::HostResponseOutparam for WasiHttpImpl where T: WasiHttpView, { @@ -583,7 +583,7 @@ where } } -impl crate::bindings::http::types::HostIncomingResponse for WasiHttpImpl +impl crate::p2::bindings::http::types::HostIncomingResponse for WasiHttpImpl where T: WasiHttpView, { @@ -647,7 +647,7 @@ where } } -impl crate::bindings::http::types::HostFutureTrailers for WasiHttpImpl +impl crate::p2::bindings::http::types::HostFutureTrailers for WasiHttpImpl where T: WasiHttpView, { @@ -697,7 +697,7 @@ where } } -impl crate::bindings::http::types::HostIncomingBody for WasiHttpImpl +impl crate::p2::bindings::http::types::HostIncomingBody for WasiHttpImpl where T: WasiHttpView, { @@ -731,7 +731,7 @@ where } } -impl crate::bindings::http::types::HostOutgoingResponse for WasiHttpImpl +impl crate::p2::bindings::http::types::HostOutgoingResponse for WasiHttpImpl where T: WasiHttpView, { @@ -826,7 +826,7 @@ where } } -impl crate::bindings::http::types::HostFutureIncomingResponse for WasiHttpImpl +impl crate::p2::bindings::http::types::HostFutureIncomingResponse for WasiHttpImpl where T: WasiHttpView, { @@ -888,7 +888,7 @@ where } } -impl crate::bindings::http::types::HostOutgoingBody for WasiHttpImpl +impl crate::p2::bindings::http::types::HostOutgoingBody for WasiHttpImpl where T: WasiHttpView, { @@ -928,7 +928,7 @@ where } } -impl crate::bindings::http::types::HostRequestOptions for WasiHttpImpl +impl crate::p2::bindings::http::types::HostRequestOptions for WasiHttpImpl where T: WasiHttpView, { diff --git a/crates/wasi-http/wit/deps/cli/command.wit b/crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/command.wit similarity index 100% rename from crates/wasi-http/wit/deps/cli/command.wit rename to crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/command.wit diff --git a/crates/wasi-http/wit/deps/cli/environment.wit b/crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/environment.wit similarity index 100% rename from crates/wasi-http/wit/deps/cli/environment.wit rename to crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/environment.wit diff --git a/crates/wasi-http/wit/deps/cli/exit.wit b/crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/exit.wit similarity index 100% rename from crates/wasi-http/wit/deps/cli/exit.wit rename to crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/exit.wit diff --git a/crates/wasi-http/wit/deps/cli/imports.wit b/crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/imports.wit similarity index 100% rename from crates/wasi-http/wit/deps/cli/imports.wit rename to crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/imports.wit diff --git a/crates/wasi-http/wit/deps/cli/run.wit b/crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/run.wit similarity index 100% rename from crates/wasi-http/wit/deps/cli/run.wit rename to crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/run.wit diff --git a/crates/wasi-http/wit/deps/cli/stdio.wit b/crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/stdio.wit similarity index 100% rename from crates/wasi-http/wit/deps/cli/stdio.wit rename to crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/stdio.wit diff --git a/crates/wasi-http/wit/deps/cli/terminal.wit b/crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/terminal.wit similarity index 100% rename from crates/wasi-http/wit/deps/cli/terminal.wit rename to crates/wasi-http/src/p2/wit/deps/cli@v0.2.3/terminal.wit diff --git a/crates/wasi-http/wit/deps/clocks/monotonic-clock.wit b/crates/wasi-http/src/p2/wit/deps/clocks@v0.2.3/monotonic-clock.wit similarity index 100% rename from crates/wasi-http/wit/deps/clocks/monotonic-clock.wit rename to crates/wasi-http/src/p2/wit/deps/clocks@v0.2.3/monotonic-clock.wit diff --git a/crates/wasi-http/wit/deps/clocks/timezone.wit b/crates/wasi-http/src/p2/wit/deps/clocks@v0.2.3/timezone.wit similarity index 100% rename from crates/wasi-http/wit/deps/clocks/timezone.wit rename to crates/wasi-http/src/p2/wit/deps/clocks@v0.2.3/timezone.wit diff --git a/crates/wasi-http/wit/deps/clocks/wall-clock.wit b/crates/wasi-http/src/p2/wit/deps/clocks@v0.2.3/wall-clock.wit similarity index 100% rename from crates/wasi-http/wit/deps/clocks/wall-clock.wit rename to crates/wasi-http/src/p2/wit/deps/clocks@v0.2.3/wall-clock.wit diff --git a/crates/wasi-http/wit/deps/clocks/world.wit b/crates/wasi-http/src/p2/wit/deps/clocks@v0.2.3/world.wit similarity index 100% rename from crates/wasi-http/wit/deps/clocks/world.wit rename to crates/wasi-http/src/p2/wit/deps/clocks@v0.2.3/world.wit diff --git a/crates/wasi-http/wit/deps/filesystem/preopens.wit b/crates/wasi-http/src/p2/wit/deps/filesystem@v0.2.3/preopens.wit similarity index 100% rename from crates/wasi-http/wit/deps/filesystem/preopens.wit rename to crates/wasi-http/src/p2/wit/deps/filesystem@v0.2.3/preopens.wit diff --git a/crates/wasi-http/wit/deps/filesystem/types.wit b/crates/wasi-http/src/p2/wit/deps/filesystem@v0.2.3/types.wit similarity index 100% rename from crates/wasi-http/wit/deps/filesystem/types.wit rename to crates/wasi-http/src/p2/wit/deps/filesystem@v0.2.3/types.wit diff --git a/crates/wasi-http/wit/deps/filesystem/world.wit b/crates/wasi-http/src/p2/wit/deps/filesystem@v0.2.3/world.wit similarity index 100% rename from crates/wasi-http/wit/deps/filesystem/world.wit rename to crates/wasi-http/src/p2/wit/deps/filesystem@v0.2.3/world.wit diff --git a/crates/wasi-http/wit/deps/http/handler.wit b/crates/wasi-http/src/p2/wit/deps/http@v0.2.3/handler.wit similarity index 100% rename from crates/wasi-http/wit/deps/http/handler.wit rename to crates/wasi-http/src/p2/wit/deps/http@v0.2.3/handler.wit diff --git a/crates/wasi-http/wit/deps/http/proxy.wit b/crates/wasi-http/src/p2/wit/deps/http@v0.2.3/proxy.wit similarity index 100% rename from crates/wasi-http/wit/deps/http/proxy.wit rename to crates/wasi-http/src/p2/wit/deps/http@v0.2.3/proxy.wit diff --git a/crates/wasi-http/wit/deps/http/types.wit b/crates/wasi-http/src/p2/wit/deps/http@v0.2.3/types.wit similarity index 100% rename from crates/wasi-http/wit/deps/http/types.wit rename to crates/wasi-http/src/p2/wit/deps/http@v0.2.3/types.wit diff --git a/crates/wasi-http/wit/deps/io/error.wit b/crates/wasi-http/src/p2/wit/deps/io@v0.2.3/error.wit similarity index 100% rename from crates/wasi-http/wit/deps/io/error.wit rename to crates/wasi-http/src/p2/wit/deps/io@v0.2.3/error.wit diff --git a/crates/wasi-http/wit/deps/io/poll.wit b/crates/wasi-http/src/p2/wit/deps/io@v0.2.3/poll.wit similarity index 100% rename from crates/wasi-http/wit/deps/io/poll.wit rename to crates/wasi-http/src/p2/wit/deps/io@v0.2.3/poll.wit diff --git a/crates/wasi-http/wit/deps/io/streams.wit b/crates/wasi-http/src/p2/wit/deps/io@v0.2.3/streams.wit similarity index 100% rename from crates/wasi-http/wit/deps/io/streams.wit rename to crates/wasi-http/src/p2/wit/deps/io@v0.2.3/streams.wit diff --git a/crates/wasi-http/wit/deps/io/world.wit b/crates/wasi-http/src/p2/wit/deps/io@v0.2.3/world.wit similarity index 100% rename from crates/wasi-http/wit/deps/io/world.wit rename to crates/wasi-http/src/p2/wit/deps/io@v0.2.3/world.wit diff --git a/crates/wasi-http/wit/deps/random/insecure-seed.wit b/crates/wasi-http/src/p2/wit/deps/random@v0.2.3/insecure-seed.wit similarity index 100% rename from crates/wasi-http/wit/deps/random/insecure-seed.wit rename to crates/wasi-http/src/p2/wit/deps/random@v0.2.3/insecure-seed.wit diff --git a/crates/wasi-http/wit/deps/random/insecure.wit b/crates/wasi-http/src/p2/wit/deps/random@v0.2.3/insecure.wit similarity index 100% rename from crates/wasi-http/wit/deps/random/insecure.wit rename to crates/wasi-http/src/p2/wit/deps/random@v0.2.3/insecure.wit diff --git a/crates/wasi-http/wit/deps/random/random.wit b/crates/wasi-http/src/p2/wit/deps/random@v0.2.3/random.wit similarity index 100% rename from crates/wasi-http/wit/deps/random/random.wit rename to crates/wasi-http/src/p2/wit/deps/random@v0.2.3/random.wit diff --git a/crates/wasi-http/wit/deps/random/world.wit b/crates/wasi-http/src/p2/wit/deps/random@v0.2.3/world.wit similarity index 100% rename from crates/wasi-http/wit/deps/random/world.wit rename to crates/wasi-http/src/p2/wit/deps/random@v0.2.3/world.wit diff --git a/crates/wasi-http/wit/deps/sockets/instance-network.wit b/crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/instance-network.wit similarity index 100% rename from crates/wasi-http/wit/deps/sockets/instance-network.wit rename to crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/instance-network.wit diff --git a/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/ip-name-lookup.wit similarity index 100% rename from crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit rename to crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/ip-name-lookup.wit diff --git a/crates/wasi-http/wit/deps/sockets/network.wit b/crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/network.wit similarity index 100% rename from crates/wasi-http/wit/deps/sockets/network.wit rename to crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/network.wit diff --git a/crates/wasi-http/wit/deps/sockets/tcp-create-socket.wit b/crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/tcp-create-socket.wit similarity index 100% rename from crates/wasi-http/wit/deps/sockets/tcp-create-socket.wit rename to crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/tcp-create-socket.wit diff --git a/crates/wasi-http/wit/deps/sockets/tcp.wit b/crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/tcp.wit similarity index 100% rename from crates/wasi-http/wit/deps/sockets/tcp.wit rename to crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/tcp.wit diff --git a/crates/wasi-http/wit/deps/sockets/udp-create-socket.wit b/crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/udp-create-socket.wit similarity index 100% rename from crates/wasi-http/wit/deps/sockets/udp-create-socket.wit rename to crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/udp-create-socket.wit diff --git a/crates/wasi-http/wit/deps/sockets/udp.wit b/crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/udp.wit similarity index 100% rename from crates/wasi-http/wit/deps/sockets/udp.wit rename to crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/udp.wit diff --git a/crates/wasi-http/wit/deps/sockets/world.wit b/crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/world.wit similarity index 100% rename from crates/wasi-http/wit/deps/sockets/world.wit rename to crates/wasi-http/src/p2/wit/deps/sockets@v0.2.3/world.wit diff --git a/crates/wasi-http/wit/world.wit b/crates/wasi-http/src/p2/wit/world.wit similarity index 100% rename from crates/wasi-http/wit/world.wit rename to crates/wasi-http/src/p2/wit/world.wit diff --git a/crates/wasi-http/src/types.rs b/crates/wasi-http/src/types.rs index 35bda46f3917..b0d84decc8d0 100644 --- a/crates/wasi-http/src/types.rs +++ b/crates/wasi-http/src/types.rs @@ -375,7 +375,7 @@ pub async fn default_send_request_handler( let (mut sender, worker) = if use_tls { #[cfg(any(target_arch = "riscv64", target_arch = "s390x"))] { - return Err(crate::bindings::http::types::ErrorCode::InternalError( + return Err(crate::p2::bindings::http::types::ErrorCode::InternalError( Some("unsupported architecture for SSL".to_string()), )); } diff --git a/crates/wasi-http/tests/all/async_.rs b/crates/wasi-http/tests/all/async_.rs index 4ea9c7c0782d..305388ab1356 100644 --- a/crates/wasi-http/tests/all/async_.rs +++ b/crates/wasi-http/tests/all/async_.rs @@ -1,6 +1,6 @@ use super::*; use test_programs_artifacts::*; -use wasmtime_wasi::bindings::Command; +use wasmtime_wasi::p2::bindings::Command; foreach_http!(assert_test_exists); diff --git a/crates/wasi-http/tests/all/sync.rs b/crates/wasi-http/tests/all/sync.rs index 64147a5a0e30..336448d07d27 100644 --- a/crates/wasi-http/tests/all/sync.rs +++ b/crates/wasi-http/tests/all/sync.rs @@ -1,6 +1,6 @@ use super::*; use test_programs_artifacts::*; -use wasmtime_wasi::bindings::sync::Command; +use wasmtime_wasi::p2::bindings::sync::Command; foreach_http!(assert_test_exists); diff --git a/crates/wasi-keyvalue/src/lib.rs b/crates/wasi-keyvalue/src/lib.rs index ce8d5b276984..b86acf656f46 100644 --- a/crates/wasi-keyvalue/src/lib.rs +++ b/crates/wasi-keyvalue/src/lib.rs @@ -67,24 +67,12 @@ #![deny(missing_docs)] -mod generated { - wasmtime::component::bindgen!({ - path: "wit", - world: "wasi:keyvalue/imports", - trappable_imports: true, - with: { - "wasi:keyvalue/store/bucket": crate::Bucket, - }, - trappable_error_type: { - "wasi:keyvalue/store/error" => crate::Error, - }, - }); -} - -use self::generated::wasi::keyvalue; -use anyhow::Result; use std::collections::HashMap; -use wasmtime::component::{Resource, ResourceTable, ResourceTableError}; +use wasmtime::component::{ResourceTable, ResourceTableError}; + +pub mod p2; +#[doc(inline)] +pub use p2::*; #[doc(hidden)] pub enum Error { @@ -162,138 +150,3 @@ impl<'a> WasiKeyValue<'a> { Self { ctx, table } } } - -impl keyvalue::store::Host for WasiKeyValue<'_> { - fn open(&mut self, identifier: String) -> Result, Error> { - match identifier.as_str() { - "" => Ok(self.table.push(Bucket { - in_memory_data: self.ctx.in_memory_data.clone(), - })?), - _ => Err(Error::NoSuchStore), - } - } - - fn convert_error(&mut self, err: Error) -> Result { - match err { - Error::NoSuchStore => Ok(keyvalue::store::Error::NoSuchStore), - Error::AccessDenied => Ok(keyvalue::store::Error::AccessDenied), - Error::Other(e) => Ok(keyvalue::store::Error::Other(e)), - } - } -} - -impl keyvalue::store::HostBucket for WasiKeyValue<'_> { - fn get(&mut self, bucket: Resource, key: String) -> Result>, Error> { - let bucket = self.table.get_mut(&bucket)?; - Ok(bucket.in_memory_data.get(&key).cloned()) - } - - fn set(&mut self, bucket: Resource, key: String, value: Vec) -> Result<(), Error> { - let bucket = self.table.get_mut(&bucket)?; - bucket.in_memory_data.insert(key, value); - Ok(()) - } - - fn delete(&mut self, bucket: Resource, key: String) -> Result<(), Error> { - let bucket = self.table.get_mut(&bucket)?; - bucket.in_memory_data.remove(&key); - Ok(()) - } - - fn exists(&mut self, bucket: Resource, key: String) -> Result { - let bucket = self.table.get_mut(&bucket)?; - Ok(bucket.in_memory_data.contains_key(&key)) - } - - fn list_keys( - &mut self, - bucket: Resource, - cursor: Option, - ) -> Result { - let bucket = self.table.get_mut(&bucket)?; - let keys: Vec = bucket.in_memory_data.keys().cloned().collect(); - let cursor = cursor.unwrap_or(0) as usize; - let keys_slice = &keys[cursor..]; - Ok(keyvalue::store::KeyResponse { - keys: keys_slice.to_vec(), - cursor: None, - }) - } - - fn drop(&mut self, bucket: Resource) -> Result<()> { - self.table.delete(bucket)?; - Ok(()) - } -} - -impl keyvalue::atomics::Host for WasiKeyValue<'_> { - fn increment( - &mut self, - bucket: Resource, - key: String, - delta: u64, - ) -> Result { - let bucket = self.table.get_mut(&bucket)?; - let value = bucket - .in_memory_data - .entry(key.clone()) - .or_insert("0".to_string().into_bytes()); - let current_value = String::from_utf8(value.clone()) - .map_err(|e| Error::Other(e.to_string()))? - .parse::() - .map_err(|e| Error::Other(e.to_string()))?; - let new_value = current_value + delta; - *value = new_value.to_string().into_bytes(); - Ok(new_value) - } -} - -impl keyvalue::batch::Host for WasiKeyValue<'_> { - fn get_many( - &mut self, - bucket: Resource, - keys: Vec, - ) -> Result)>>, Error> { - let bucket = self.table.get_mut(&bucket)?; - Ok(keys - .into_iter() - .map(|key| { - bucket - .in_memory_data - .get(&key) - .map(|value| (key.clone(), value.clone())) - }) - .collect()) - } - - fn set_many( - &mut self, - bucket: Resource, - key_values: Vec<(String, Vec)>, - ) -> Result<(), Error> { - let bucket = self.table.get_mut(&bucket)?; - for (key, value) in key_values { - bucket.in_memory_data.insert(key, value); - } - Ok(()) - } - - fn delete_many(&mut self, bucket: Resource, keys: Vec) -> Result<(), Error> { - let bucket = self.table.get_mut(&bucket)?; - for key in keys { - bucket.in_memory_data.remove(&key); - } - Ok(()) - } -} - -/// Add all the `wasi-keyvalue` world's interfaces to a [`wasmtime::component::Linker`]. -pub fn add_to_linker( - l: &mut wasmtime::component::Linker, - f: impl Fn(&mut T) -> WasiKeyValue<'_> + Send + Sync + Copy + 'static, -) -> Result<()> { - keyvalue::store::add_to_linker_get_host(l, f)?; - keyvalue::atomics::add_to_linker_get_host(l, f)?; - keyvalue::batch::add_to_linker_get_host(l, f)?; - Ok(()) -} diff --git a/crates/wasi-keyvalue/src/p2/mod.rs b/crates/wasi-keyvalue/src/p2/mod.rs new file mode 100644 index 000000000000..5ead357be277 --- /dev/null +++ b/crates/wasi-keyvalue/src/p2/mod.rs @@ -0,0 +1,157 @@ +//! Implementation of wasip2 version of `wasi:keyvalue` package + +mod generated { + wasmtime::component::bindgen!({ + path: "src/p2/wit", + world: "wasi:keyvalue/imports", + trappable_imports: true, + with: { + "wasi:keyvalue/store/bucket": crate::Bucket, + }, + trappable_error_type: { + "wasi:keyvalue/store/error" => crate::Error, + }, + }); +} + +use self::generated::wasi::keyvalue; + +use anyhow::Result; +use wasmtime::component::Resource; + +use crate::{Bucket, Error, WasiKeyValue}; + +impl keyvalue::store::Host for WasiKeyValue<'_> { + fn open(&mut self, identifier: String) -> Result, Error> { + match identifier.as_str() { + "" => Ok(self.table.push(Bucket { + in_memory_data: self.ctx.in_memory_data.clone(), + })?), + _ => Err(Error::NoSuchStore), + } + } + + fn convert_error(&mut self, err: Error) -> Result { + match err { + Error::NoSuchStore => Ok(keyvalue::store::Error::NoSuchStore), + Error::AccessDenied => Ok(keyvalue::store::Error::AccessDenied), + Error::Other(e) => Ok(keyvalue::store::Error::Other(e)), + } + } +} + +impl keyvalue::store::HostBucket for WasiKeyValue<'_> { + fn get(&mut self, bucket: Resource, key: String) -> Result>, Error> { + let bucket = self.table.get_mut(&bucket)?; + Ok(bucket.in_memory_data.get(&key).cloned()) + } + + fn set(&mut self, bucket: Resource, key: String, value: Vec) -> Result<(), Error> { + let bucket = self.table.get_mut(&bucket)?; + bucket.in_memory_data.insert(key, value); + Ok(()) + } + + fn delete(&mut self, bucket: Resource, key: String) -> Result<(), Error> { + let bucket = self.table.get_mut(&bucket)?; + bucket.in_memory_data.remove(&key); + Ok(()) + } + + fn exists(&mut self, bucket: Resource, key: String) -> Result { + let bucket = self.table.get_mut(&bucket)?; + Ok(bucket.in_memory_data.contains_key(&key)) + } + + fn list_keys( + &mut self, + bucket: Resource, + cursor: Option, + ) -> Result { + let bucket = self.table.get_mut(&bucket)?; + let keys: Vec = bucket.in_memory_data.keys().cloned().collect(); + let cursor = cursor.unwrap_or(0) as usize; + let keys_slice = &keys[cursor..]; + Ok(keyvalue::store::KeyResponse { + keys: keys_slice.to_vec(), + cursor: None, + }) + } + + fn drop(&mut self, bucket: Resource) -> Result<()> { + self.table.delete(bucket)?; + Ok(()) + } +} + +impl keyvalue::atomics::Host for WasiKeyValue<'_> { + fn increment( + &mut self, + bucket: Resource, + key: String, + delta: u64, + ) -> Result { + let bucket = self.table.get_mut(&bucket)?; + let value = bucket + .in_memory_data + .entry(key.clone()) + .or_insert("0".to_string().into_bytes()); + let current_value = String::from_utf8(value.clone()) + .map_err(|e| Error::Other(e.to_string()))? + .parse::() + .map_err(|e| Error::Other(e.to_string()))?; + let new_value = current_value + delta; + *value = new_value.to_string().into_bytes(); + Ok(new_value) + } +} + +impl keyvalue::batch::Host for WasiKeyValue<'_> { + fn get_many( + &mut self, + bucket: Resource, + keys: Vec, + ) -> Result)>>, Error> { + let bucket = self.table.get_mut(&bucket)?; + Ok(keys + .into_iter() + .map(|key| { + bucket + .in_memory_data + .get(&key) + .map(|value| (key.clone(), value.clone())) + }) + .collect()) + } + + fn set_many( + &mut self, + bucket: Resource, + key_values: Vec<(String, Vec)>, + ) -> Result<(), Error> { + let bucket = self.table.get_mut(&bucket)?; + for (key, value) in key_values { + bucket.in_memory_data.insert(key, value); + } + Ok(()) + } + + fn delete_many(&mut self, bucket: Resource, keys: Vec) -> Result<(), Error> { + let bucket = self.table.get_mut(&bucket)?; + for key in keys { + bucket.in_memory_data.remove(&key); + } + Ok(()) + } +} + +/// Add all the `wasi-keyvalue` world's interfaces to a [`wasmtime::component::Linker`]. +pub fn add_to_linker( + l: &mut wasmtime::component::Linker, + f: impl Fn(&mut T) -> WasiKeyValue<'_> + Send + Sync + Copy + 'static, +) -> Result<()> { + keyvalue::store::add_to_linker_get_host(l, f)?; + keyvalue::atomics::add_to_linker_get_host(l, f)?; + keyvalue::batch::add_to_linker_get_host(l, f)?; + Ok(()) +} diff --git a/crates/wasi-keyvalue/wit/deps/keyvalue/atomic.wit b/crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/atomic.wit similarity index 100% rename from crates/wasi-keyvalue/wit/deps/keyvalue/atomic.wit rename to crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/atomic.wit diff --git a/crates/wasi-keyvalue/wit/deps/keyvalue/batch.wit b/crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/batch.wit similarity index 100% rename from crates/wasi-keyvalue/wit/deps/keyvalue/batch.wit rename to crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/batch.wit diff --git a/crates/wasi-keyvalue/wit/deps/keyvalue/store.wit b/crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/store.wit similarity index 100% rename from crates/wasi-keyvalue/wit/deps/keyvalue/store.wit rename to crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/store.wit diff --git a/crates/wasi-keyvalue/wit/deps/keyvalue/watch.wit b/crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/watch.wit similarity index 100% rename from crates/wasi-keyvalue/wit/deps/keyvalue/watch.wit rename to crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/watch.wit diff --git a/crates/wasi-keyvalue/wit/deps/keyvalue/world.wit b/crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/world.wit similarity index 100% rename from crates/wasi-keyvalue/wit/deps/keyvalue/world.wit rename to crates/wasi-keyvalue/src/p2/wit/deps/keyvalue@219ea36/world.wit diff --git a/crates/wasi-keyvalue/wit/world.wit b/crates/wasi-keyvalue/src/p2/wit/world.wit similarity index 100% rename from crates/wasi-keyvalue/wit/world.wit rename to crates/wasi-keyvalue/src/p2/wit/world.wit diff --git a/crates/wasi-nn/tests/exec/wit.rs b/crates/wasi-nn/tests/exec/wit.rs index 21a756c4ddf8..87b46489b516 100644 --- a/crates/wasi-nn/tests/exec/wit.rs +++ b/crates/wasi-nn/tests/exec/wit.rs @@ -4,7 +4,7 @@ use anyhow::{anyhow, Result}; use std::path::Path; use wasmtime::component::{Component, Linker, ResourceTable}; use wasmtime::{Config, Engine, Store}; -use wasmtime_wasi::bindings::sync::Command; +use wasmtime_wasi::p2::bindings::sync::Command; use wasmtime_wasi::{DirPerms, FilePerms, WasiCtx, WasiCtxBuilder}; use wasmtime_wasi_nn::wit::WasiNnView; use wasmtime_wasi_nn::{wit::WasiNnCtx, Backend, InMemoryRegistry}; diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs index ad077ca9ed9b..fef8e08d6548 100644 --- a/crates/wasi-preview1-component-adapter/src/lib.rs +++ b/crates/wasi-preview1-component-adapter/src/lib.rs @@ -52,7 +52,7 @@ use crate::descriptors::{Descriptor, Descriptors, StreamType, Streams}; pub mod bindings { #[cfg(feature = "command")] wit_bindgen_rust_macro::generate!({ - path: "../wasi/wit", + path: "../wasi/src/p2/wit", world: "wasi:cli/command", raw_strings, runtime_path: "crate::bindings::wit_bindgen_rt_shim", @@ -69,7 +69,7 @@ pub mod bindings { #[cfg(feature = "reactor")] wit_bindgen_rust_macro::generate!({ - path: "../wasi/wit", + path: "../wasi/src/p2/wit", world: "wasi:cli/imports", raw_strings, runtime_path: "crate::bindings::wit_bindgen_rt_shim", @@ -86,7 +86,7 @@ pub mod bindings { #[cfg(feature = "proxy")] wit_bindgen_rust_macro::generate!({ - path: "../wasi-http/wit", + path: "../wasi-http/src/p2/wit", inline: r#" package wasmtime:adapter; diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml index db02061ce315..b982f94414e8 100644 --- a/crates/wasi/Cargo.toml +++ b/crates/wasi/Cargo.toml @@ -57,6 +57,8 @@ default = [ "preview1"] preview1 = [ "dep:wiggle", ] +# Enables experimental, unstable and incomplete support for wasip3 +p3 = [] [[test]] name = "process_stdin" diff --git a/crates/wasi/src/ctx.rs b/crates/wasi/src/ctx.rs index b86895712a9e..25ef1c512766 100644 --- a/crates/wasi/src/ctx.rs +++ b/crates/wasi/src/ctx.rs @@ -560,9 +560,9 @@ impl WasiCtxBuilder { /// Per-[`Store`] state which holds state necessary to implement WASI from this /// crate. /// -/// This structure is created through [`WasiCtxBuilder`] and is stored within +/// This structure is created through [`WasiCtxBuilder`](crate::WasiCtxBuilder) and is stored within /// the `T` of [`Store`][`Store`]. Access to the structure is provided -/// through the [`WasiView`] trait as an implementation on `T`. +/// through the [`WasiView`](crate::WasiView) trait as an implementation on `T`. /// /// Note that this structure itself does not have any accessors, it's here for /// internal use within the `wasmtime-wasi` crate's implementation of diff --git a/crates/wasi/src/filesystem.rs b/crates/wasi/src/filesystem.rs index 2c6f039de4f0..f49993ca1292 100644 --- a/crates/wasi/src/filesystem.rs +++ b/crates/wasi/src/filesystem.rs @@ -1,4 +1,4 @@ -use crate::bindings::filesystem::types; +use crate::p2::bindings::filesystem::types; use crate::runtime::{spawn_blocking, AbortOnDropJoinHandle}; use crate::{ HostInputStream, HostOutputStream, StreamError, StreamResult, Subscribe, TrappableError, diff --git a/crates/wasi/src/ip_name_lookup.rs b/crates/wasi/src/ip_name_lookup.rs index 8ed47b0d1e50..b514e3a83a48 100644 --- a/crates/wasi/src/ip_name_lookup.rs +++ b/crates/wasi/src/ip_name_lookup.rs @@ -1,6 +1,6 @@ -use crate::bindings::sockets::ip_name_lookup::{Host, HostResolveAddressStream}; -use crate::bindings::sockets::network::{ErrorCode, IpAddress, Network}; use crate::host::network::util; +use crate::p2::bindings::sockets::ip_name_lookup::{Host, HostResolveAddressStream}; +use crate::p2::bindings::sockets::network::{ErrorCode, IpAddress, Network}; use crate::poll::{subscribe, Pollable, Subscribe}; use crate::runtime::{spawn_blocking, AbortOnDropJoinHandle}; use crate::{IoView, SocketError, WasiImpl, WasiView}; diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs index 58375b784f70..04f919b2bf0d 100644 --- a/crates/wasi/src/lib.rs +++ b/crates/wasi/src/lib.rs @@ -183,16 +183,15 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![expect(clippy::allow_attributes_without_reason, reason = "crate not migrated")] -use wasmtime::component::Linker; - -pub mod bindings; mod clocks; mod ctx; mod error; mod filesystem; -mod host; mod ip_name_lookup; mod network; +pub mod p2; +#[cfg(feature = "p3")] +pub mod p3; pub mod pipe; mod poll; #[cfg(feature = "preview1")] @@ -229,212 +228,11 @@ pub use async_trait::async_trait; pub use cap_fs_ext::SystemTimeSpec; #[doc(no_inline)] pub use cap_rand::RngCore; +#[doc(inline)] +pub use p2::*; #[doc(no_inline)] pub use wasmtime::component::{ResourceTable, ResourceTableError}; -/// Add all WASI interfaces from this crate into the `linker` provided. -/// -/// This function will add the `async` variant of all interfaces into the -/// [`Linker`] provided. By `async` this means that this function is only -/// compatible with [`Config::async_support(true)`][async]. For embeddings with -/// async support disabled see [`add_to_linker_sync`] instead. -/// -/// This function will add all interfaces implemented by this crate to the -/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by -/// this crate. -/// -/// [async]: wasmtime::Config::async_support -/// -/// # Example -/// -/// ``` -/// use wasmtime::{Engine, Result, Store, Config}; -/// use wasmtime::component::{ResourceTable, Linker}; -/// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; -/// -/// fn main() -> Result<()> { -/// let mut config = Config::new(); -/// config.async_support(true); -/// let engine = Engine::new(&config)?; -/// -/// let mut linker = Linker::::new(&engine); -/// wasmtime_wasi::add_to_linker_async(&mut linker)?; -/// // ... add any further functionality to `linker` if desired ... -/// -/// let mut builder = WasiCtxBuilder::new(); -/// -/// // ... configure `builder` more to add env vars, args, etc ... -/// -/// let mut store = Store::new( -/// &engine, -/// MyState { -/// ctx: builder.build(), -/// table: ResourceTable::new(), -/// }, -/// ); -/// -/// // ... use `linker` to instantiate within `store` ... -/// -/// Ok(()) -/// } -/// -/// struct MyState { -/// ctx: WasiCtx, -/// table: ResourceTable, -/// } -/// -/// impl IoView for MyState { -/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } -/// } -/// impl WasiView for MyState { -/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } -/// } -/// ``` -pub fn add_to_linker_async(linker: &mut Linker) -> anyhow::Result<()> { - let options = crate::bindings::LinkOptions::default(); - add_to_linker_with_options_async(linker, &options) -} - -/// Similar to [`add_to_linker_async`], but with the ability to enable unstable features. -pub fn add_to_linker_with_options_async( - linker: &mut Linker, - options: &crate::bindings::LinkOptions, -) -> anyhow::Result<()> { - let l = linker; - let io_closure = io_type_annotate::(|t| IoImpl(t)); - let closure = type_annotate::(|t| WasiImpl(IoImpl(t))); - - crate::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; - crate::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; - crate::bindings::filesystem::types::add_to_linker_get_host(l, closure)?; - crate::bindings::filesystem::preopens::add_to_linker_get_host(l, closure)?; - crate::bindings::io::error::add_to_linker_get_host(l, io_closure)?; - crate::bindings::io::poll::add_to_linker_get_host(l, io_closure)?; - crate::bindings::io::streams::add_to_linker_get_host(l, io_closure)?; - crate::bindings::random::random::add_to_linker_get_host(l, closure)?; - crate::bindings::random::insecure::add_to_linker_get_host(l, closure)?; - crate::bindings::random::insecure_seed::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::exit::add_to_linker_get_host(l, &options.into(), closure)?; - crate::bindings::cli::environment::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::stdin::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::stdout::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::stderr::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_input::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_output::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_stdin::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_stdout::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_stderr::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::tcp::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::tcp_create_socket::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::udp::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::udp_create_socket::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::instance_network::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::network::add_to_linker_get_host(l, &options.into(), closure)?; - crate::bindings::sockets::ip_name_lookup::add_to_linker_get_host(l, closure)?; - Ok(()) -} - -/// Add all WASI interfaces from this crate into the `linker` provided. -/// -/// This function will add the synchronous variant of all interfaces into the -/// [`Linker`] provided. By synchronous this means that this function is only -/// compatible with [`Config::async_support(false)`][async]. For embeddings -/// with async support enabled see [`add_to_linker_async`] instead. -/// -/// This function will add all interfaces implemented by this crate to the -/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by -/// this crate. -/// -/// [async]: wasmtime::Config::async_support -/// -/// # Example -/// -/// ``` -/// use wasmtime::{Engine, Result, Store, Config}; -/// use wasmtime::component::{ResourceTable, Linker}; -/// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; -/// -/// fn main() -> Result<()> { -/// let engine = Engine::default(); -/// -/// let mut linker = Linker::::new(&engine); -/// wasmtime_wasi::add_to_linker_sync(&mut linker)?; -/// // ... add any further functionality to `linker` if desired ... -/// -/// let mut builder = WasiCtxBuilder::new(); -/// -/// // ... configure `builder` more to add env vars, args, etc ... -/// -/// let mut store = Store::new( -/// &engine, -/// MyState { -/// ctx: builder.build(), -/// table: ResourceTable::new(), -/// }, -/// ); -/// -/// // ... use `linker` to instantiate within `store` ... -/// -/// Ok(()) -/// } -/// -/// struct MyState { -/// ctx: WasiCtx, -/// table: ResourceTable, -/// } -/// impl IoView for MyState { -/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } -/// } -/// impl WasiView for MyState { -/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } -/// } -/// ``` -pub fn add_to_linker_sync( - linker: &mut wasmtime::component::Linker, -) -> anyhow::Result<()> { - let options = crate::bindings::sync::LinkOptions::default(); - add_to_linker_with_options_sync(linker, &options) -} - -/// Similar to [`add_to_linker_sync`], but with the ability to enable unstable features. -pub fn add_to_linker_with_options_sync( - linker: &mut wasmtime::component::Linker, - options: &crate::bindings::sync::LinkOptions, -) -> anyhow::Result<()> { - let l = linker; - let io_closure = io_type_annotate::(|t| IoImpl(t)); - let closure = type_annotate::(|t| WasiImpl(IoImpl(t))); - - crate::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; - crate::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; - crate::bindings::sync::filesystem::types::add_to_linker_get_host(l, closure)?; - crate::bindings::filesystem::preopens::add_to_linker_get_host(l, closure)?; - crate::bindings::io::error::add_to_linker_get_host(l, io_closure)?; - crate::bindings::sync::io::poll::add_to_linker_get_host(l, io_closure)?; - crate::bindings::sync::io::streams::add_to_linker_get_host(l, io_closure)?; - crate::bindings::random::random::add_to_linker_get_host(l, closure)?; - crate::bindings::random::insecure::add_to_linker_get_host(l, closure)?; - crate::bindings::random::insecure_seed::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::exit::add_to_linker_get_host(l, &options.into(), closure)?; - crate::bindings::cli::environment::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::stdin::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::stdout::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::stderr::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_input::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_output::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_stdin::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_stdout::add_to_linker_get_host(l, closure)?; - crate::bindings::cli::terminal_stderr::add_to_linker_get_host(l, closure)?; - crate::bindings::sync::sockets::tcp::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::tcp_create_socket::add_to_linker_get_host(l, closure)?; - crate::bindings::sync::sockets::udp::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::udp_create_socket::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::instance_network::add_to_linker_get_host(l, closure)?; - crate::bindings::sockets::network::add_to_linker_get_host(l, &options.into(), closure)?; - crate::bindings::sockets::ip_name_lookup::add_to_linker_get_host(l, closure)?; - Ok(()) -} - // NB: workaround some rustc inference - a future refactoring may make this // obsolete. fn io_type_annotate(val: F) -> F diff --git a/crates/wasi/src/network.rs b/crates/wasi/src/network.rs index c435accf213f..4cdeb8c6cd69 100644 --- a/crates/wasi/src/network.rs +++ b/crates/wasi/src/network.rs @@ -1,4 +1,4 @@ -use crate::bindings::sockets::network::{ErrorCode, Ipv4Address, Ipv6Address}; +use crate::p2::bindings::sockets::network::{ErrorCode, Ipv4Address, Ipv6Address}; use crate::TrappableError; use std::future::Future; use std::net::SocketAddr; diff --git a/crates/wasi/src/bindings.rs b/crates/wasi/src/p2/bindings.rs similarity index 95% rename from crates/wasi/src/bindings.rs rename to crates/wasi/src/p2/bindings.rs index 7449b3a3f202..1a00e1e34be3 100644 --- a/crates/wasi/src/bindings.rs +++ b/crates/wasi/src/p2/bindings.rs @@ -35,9 +35,9 @@ //! my-custom-function: func(); //! } //! ", -//! path: "wit", +//! path: "src/p2/wit", //! with: { -//! "wasi": wasmtime_wasi::bindings, +//! "wasi": wasmtime_wasi::p2::bindings, //! }, //! async: true, //! }); @@ -76,7 +76,7 @@ /// Synchronous-generated bindings for WASI interfaces. /// -/// This is the same as the top-level [`bindings`](crate::bindings) module of +/// This is the same as the top-level [`bindings`](crate::p2::bindings) module of /// this crate except that it's for synchronous calls. /// /// # Examples @@ -106,9 +106,9 @@ /// my-custom-function: func(); /// } /// ", -/// path: "wit", +/// path: "src/p2/wit", /// with: { -/// "wasi": wasmtime_wasi::bindings::sync, +/// "wasi": wasmtime_wasi::p2::bindings::sync, /// }, /// // This is required for bindings using `wasmtime-wasi` and it otherwise /// // isn't the default for non-async bindings. @@ -149,7 +149,7 @@ pub mod sync { use crate::{FsError, SocketError, StreamError}; wasmtime::component::bindgen!({ - path: "wit", + path: "src/p2/wit", world: "wasi:cli/command", tracing: true, trappable_error_type: { @@ -161,12 +161,12 @@ pub mod sync { with: { // These interfaces come from the outer module, as it's // sync/async agnostic. - "wasi:clocks": crate::bindings::clocks, - "wasi:random": crate::bindings::random, - "wasi:cli": crate::bindings::cli, - "wasi:io/error": crate::bindings::io::error, - "wasi:filesystem/preopens": crate::bindings::filesystem::preopens, - "wasi:sockets/network": crate::bindings::sockets::network, + "wasi:clocks": crate::p2::bindings::clocks, + "wasi:random": crate::p2::bindings::random, + "wasi:cli": crate::p2::bindings::cli, + "wasi:io/error": crate::p2::bindings::io::error, + "wasi:filesystem/preopens": crate::p2::bindings::filesystem::preopens, + "wasi:sockets/network": crate::p2::bindings::sockets::network, // Configure the resource types of the bound interfaces here // to be the same as the async versions of the resources, that @@ -206,7 +206,7 @@ pub mod sync { /// use wasmtime::{Engine, Result, Store, Config}; /// use wasmtime::component::{ResourceTable, Linker, Component}; /// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; - /// use wasmtime_wasi::bindings::sync::Command; + /// use wasmtime_wasi::p2::bindings::sync::Command; /// /// // This example is an example shim of executing a component based on the /// // command line arguments provided to this program. @@ -271,7 +271,7 @@ pub mod sync { /// use wasmtime::{Engine, Result, Store, Config}; /// use wasmtime::component::{ResourceTable, Linker, Component}; /// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; - /// use wasmtime_wasi::bindings::sync::CommandPre; + /// use wasmtime_wasi::p2::bindings::sync::CommandPre; /// /// // This example is an example shim of executing a component based on the /// // command line arguments provided to this program. @@ -333,7 +333,7 @@ pub mod sync { mod async_io { wasmtime::component::bindgen!({ - path: "wit", + path: "src/p2/wit", world: "wasi:cli/command", tracing: true, trappable_imports: true, @@ -448,7 +448,7 @@ pub use self::async_io::LinkOptions; /// use wasmtime::{Engine, Result, Store, Config}; /// use wasmtime::component::{ResourceTable, Linker, Component}; /// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; -/// use wasmtime_wasi::bindings::Command; +/// use wasmtime_wasi::p2::bindings::Command; /// /// // This example is an example shim of executing a component based on the /// // command line arguments provided to this program. @@ -516,7 +516,7 @@ pub use self::async_io::Command; /// use wasmtime::{Engine, Result, Store, Config}; /// use wasmtime::component::{ResourceTable, Linker, Component}; /// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; -/// use wasmtime_wasi::bindings::CommandPre; +/// use wasmtime_wasi::p2::bindings::CommandPre; /// /// // This example is an example shim of executing a component based on the /// // command line arguments provided to this program. diff --git a/crates/wasi/src/host/clocks.rs b/crates/wasi/src/p2/host/clocks.rs similarity index 98% rename from crates/wasi/src/host/clocks.rs rename to crates/wasi/src/p2/host/clocks.rs index feefb9473b27..2bbfba9333bb 100644 --- a/crates/wasi/src/host/clocks.rs +++ b/crates/wasi/src/p2/host/clocks.rs @@ -1,6 +1,6 @@ #![allow(unused_variables)] -use crate::bindings::{ +use crate::p2::bindings::{ clocks::monotonic_clock::{self, Duration as WasiDuration, Instant}, clocks::wall_clock::{self, Datetime}, }; @@ -17,7 +17,7 @@ impl TryFrom for Datetime { let duration = time.duration_since(SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH))?; - Ok(Datetime { + Ok(Self { seconds: duration.as_secs(), nanoseconds: duration.subsec_nanos(), }) diff --git a/crates/wasi/src/host/env.rs b/crates/wasi/src/p2/host/env.rs similarity index 91% rename from crates/wasi/src/host/env.rs rename to crates/wasi/src/p2/host/env.rs index db259d8caa14..fe688277d6cf 100644 --- a/crates/wasi/src/host/env.rs +++ b/crates/wasi/src/p2/host/env.rs @@ -1,4 +1,4 @@ -use crate::bindings::cli::environment; +use crate::p2::bindings::cli::environment; use crate::{WasiImpl, WasiView}; impl environment::Host for WasiImpl diff --git a/crates/wasi/src/host/exit.rs b/crates/wasi/src/p2/host/exit.rs similarity index 100% rename from crates/wasi/src/host/exit.rs rename to crates/wasi/src/p2/host/exit.rs diff --git a/crates/wasi/src/host/filesystem.rs b/crates/wasi/src/p2/host/filesystem.rs similarity index 99% rename from crates/wasi/src/host/filesystem.rs rename to crates/wasi/src/p2/host/filesystem.rs index a8cfb91754f3..23c8252e3b19 100644 --- a/crates/wasi/src/host/filesystem.rs +++ b/crates/wasi/src/p2/host/filesystem.rs @@ -1,12 +1,12 @@ -use crate::bindings::clocks::wall_clock; -use crate::bindings::filesystem::preopens; -use crate::bindings::filesystem::types::{ - self, ErrorCode, HostDescriptor, HostDirectoryEntryStream, -}; -use crate::bindings::io::streams::{InputStream, OutputStream}; use crate::filesystem::{ Descriptor, Dir, File, FileInputStream, FileOutputStream, OpenMode, ReaddirIterator, }; +use crate::p2::bindings::clocks::wall_clock; +use crate::p2::bindings::filesystem::preopens; +use crate::p2::bindings::filesystem::types::{ + self, ErrorCode, HostDescriptor, HostDirectoryEntryStream, +}; +use crate::p2::bindings::io::streams::{InputStream, OutputStream}; use crate::{DirPerms, FilePerms, FsError, FsResult, IoView, WasiImpl, WasiView}; use anyhow::Context; use wasmtime::component::Resource; diff --git a/crates/wasi/src/host/filesystem/sync.rs b/crates/wasi/src/p2/host/filesystem/sync.rs similarity index 99% rename from crates/wasi/src/host/filesystem/sync.rs rename to crates/wasi/src/p2/host/filesystem/sync.rs index 5de6b051921d..c12f515255c7 100644 --- a/crates/wasi/src/host/filesystem/sync.rs +++ b/crates/wasi/src/p2/host/filesystem/sync.rs @@ -1,6 +1,6 @@ -use crate::bindings::filesystem::types as async_filesystem; -use crate::bindings::sync::filesystem::types as sync_filesystem; -use crate::bindings::sync::io::streams; +use crate::p2::bindings::filesystem::types as async_filesystem; +use crate::p2::bindings::sync::filesystem::types as sync_filesystem; +use crate::p2::bindings::sync::io::streams; use crate::runtime::in_tokio; use crate::{FsError, FsResult, WasiImpl, WasiView}; use wasmtime::component::Resource; diff --git a/crates/wasi/src/host/instance_network.rs b/crates/wasi/src/p2/host/instance_network.rs similarity index 91% rename from crates/wasi/src/host/instance_network.rs rename to crates/wasi/src/p2/host/instance_network.rs index d6b06718a8d0..77129ae49e8b 100644 --- a/crates/wasi/src/host/instance_network.rs +++ b/crates/wasi/src/p2/host/instance_network.rs @@ -1,5 +1,5 @@ -use crate::bindings::sockets::instance_network; use crate::network::Network; +use crate::p2::bindings::sockets::instance_network; use crate::{IoView, WasiImpl, WasiView}; use wasmtime::component::Resource; diff --git a/crates/wasi/src/host/io.rs b/crates/wasi/src/p2/host/io.rs similarity index 100% rename from crates/wasi/src/host/io.rs rename to crates/wasi/src/p2/host/io.rs diff --git a/crates/wasi/src/host/mod.rs b/crates/wasi/src/p2/host/mod.rs similarity index 100% rename from crates/wasi/src/host/mod.rs rename to crates/wasi/src/p2/host/mod.rs diff --git a/crates/wasi/src/host/network.rs b/crates/wasi/src/p2/host/network.rs similarity index 99% rename from crates/wasi/src/host/network.rs rename to crates/wasi/src/p2/host/network.rs index e7de7e92b656..b97507aa764f 100644 --- a/crates/wasi/src/host/network.rs +++ b/crates/wasi/src/p2/host/network.rs @@ -1,8 +1,8 @@ -use crate::bindings::sockets::network::{ +use crate::network::{from_ipv4_addr, from_ipv6_addr, to_ipv4_addr, to_ipv6_addr}; +use crate::p2::bindings::sockets::network::{ self, ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress, Ipv6SocketAddress, }; -use crate::network::{from_ipv4_addr, from_ipv6_addr, to_ipv4_addr, to_ipv6_addr}; use crate::{IoView, SocketError, WasiImpl, WasiView}; use anyhow::Error; use rustix::io::Errno; @@ -28,7 +28,7 @@ where } } -impl crate::bindings::sockets::network::HostNetwork for WasiImpl +impl crate::p2::bindings::sockets::network::HostNetwork for WasiImpl where T: WasiView, { diff --git a/crates/wasi/src/host/random.rs b/crates/wasi/src/p2/host/random.rs similarity index 94% rename from crates/wasi/src/host/random.rs rename to crates/wasi/src/p2/host/random.rs index a3fe59487d3f..4a1c5f506e6c 100644 --- a/crates/wasi/src/host/random.rs +++ b/crates/wasi/src/p2/host/random.rs @@ -1,4 +1,4 @@ -use crate::bindings::random::{insecure, insecure_seed, random}; +use crate::p2::bindings::random::{insecure, insecure_seed, random}; use crate::{WasiImpl, WasiView}; use cap_rand::{distributions::Standard, Rng}; diff --git a/crates/wasi/src/host/tcp.rs b/crates/wasi/src/p2/host/tcp.rs similarity index 100% rename from crates/wasi/src/host/tcp.rs rename to crates/wasi/src/p2/host/tcp.rs diff --git a/crates/wasi/src/host/tcp_create_socket.rs b/crates/wasi/src/p2/host/tcp_create_socket.rs similarity index 83% rename from crates/wasi/src/host/tcp_create_socket.rs rename to crates/wasi/src/p2/host/tcp_create_socket.rs index 4c846295f552..c5ba863d8a96 100644 --- a/crates/wasi/src/host/tcp_create_socket.rs +++ b/crates/wasi/src/p2/host/tcp_create_socket.rs @@ -1,4 +1,4 @@ -use crate::bindings::{sockets::network::IpAddressFamily, sockets::tcp_create_socket}; +use crate::p2::bindings::{sockets::network::IpAddressFamily, sockets::tcp_create_socket}; use crate::tcp::TcpSocket; use crate::{IoView, SocketResult, WasiImpl, WasiView}; use wasmtime::component::Resource; diff --git a/crates/wasi/src/host/udp.rs b/crates/wasi/src/p2/host/udp.rs similarity index 100% rename from crates/wasi/src/host/udp.rs rename to crates/wasi/src/p2/host/udp.rs diff --git a/crates/wasi/src/host/udp_create_socket.rs b/crates/wasi/src/p2/host/udp_create_socket.rs similarity index 83% rename from crates/wasi/src/host/udp_create_socket.rs rename to crates/wasi/src/p2/host/udp_create_socket.rs index 533b4d7d5c92..d08e420b9e50 100644 --- a/crates/wasi/src/host/udp_create_socket.rs +++ b/crates/wasi/src/p2/host/udp_create_socket.rs @@ -1,4 +1,4 @@ -use crate::bindings::{sockets::network::IpAddressFamily, sockets::udp_create_socket}; +use crate::p2::bindings::{sockets::network::IpAddressFamily, sockets::udp_create_socket}; use crate::udp::UdpSocket; use crate::{IoView, SocketResult, WasiImpl, WasiView}; use wasmtime::component::Resource; diff --git a/crates/wasi/src/p2/mod.rs b/crates/wasi/src/p2/mod.rs new file mode 100644 index 000000000000..41c39a51ec94 --- /dev/null +++ b/crates/wasi/src/p2/mod.rs @@ -0,0 +1,211 @@ +//! Implementation of wasip2 version of WASI + +use wasmtime::component::Linker; + +use crate::{io_type_annotate, type_annotate, IoImpl, WasiImpl, WasiView}; + +pub mod bindings; +pub(crate) mod host; + +/// Add all WASI interfaces from this module into the `linker` provided. +/// +/// This function will add the `async` variant of all interfaces into the +/// [`Linker`] provided. By `async` this means that this function is only +/// compatible with [`Config::async_support(true)`][async]. For embeddings with +/// async support disabled see [`add_to_linker_sync`] instead. +/// +/// This function will add all interfaces implemented by this crate to the +/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by +/// this crate. +/// +/// [async]: wasmtime::Config::async_support +/// +/// # Example +/// +/// ``` +/// use wasmtime::{Engine, Result, Store, Config}; +/// use wasmtime::component::{ResourceTable, Linker}; +/// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; +/// +/// fn main() -> Result<()> { +/// let mut config = Config::new(); +/// config.async_support(true); +/// let engine = Engine::new(&config)?; +/// +/// let mut linker = Linker::::new(&engine); +/// wasmtime_wasi::add_to_linker_async(&mut linker)?; +/// // ... add any further functionality to `linker` if desired ... +/// +/// let mut builder = WasiCtxBuilder::new(); +/// +/// // ... configure `builder` more to add env vars, args, etc ... +/// +/// let mut store = Store::new( +/// &engine, +/// MyState { +/// ctx: builder.build(), +/// table: ResourceTable::new(), +/// }, +/// ); +/// +/// // ... use `linker` to instantiate within `store` ... +/// +/// Ok(()) +/// } +/// +/// struct MyState { +/// ctx: WasiCtx, +/// table: ResourceTable, +/// } +/// +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// ``` +pub fn add_to_linker_async(linker: &mut Linker) -> anyhow::Result<()> { + let options = crate::p2::bindings::LinkOptions::default(); + add_to_linker_with_options_async(linker, &options) +} + +/// Similar to [`add_to_linker_async`], but with the ability to enable unstable features. +pub fn add_to_linker_with_options_async( + linker: &mut Linker, + options: &crate::p2::bindings::LinkOptions, +) -> anyhow::Result<()> { + let l = linker; + let io_closure = io_type_annotate::(|t| IoImpl(t)); + let closure = type_annotate::(|t| WasiImpl(IoImpl(t))); + + crate::p2::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::filesystem::types::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::filesystem::preopens::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::io::error::add_to_linker_get_host(l, io_closure)?; + crate::p2::bindings::io::poll::add_to_linker_get_host(l, io_closure)?; + crate::p2::bindings::io::streams::add_to_linker_get_host(l, io_closure)?; + crate::p2::bindings::random::random::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::random::insecure::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::random::insecure_seed::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::exit::add_to_linker_get_host(l, &options.into(), closure)?; + crate::p2::bindings::cli::environment::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::stdin::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::stdout::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::stderr::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_input::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_output::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_stdin::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_stdout::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_stderr::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::tcp::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::tcp_create_socket::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::udp::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::udp_create_socket::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::instance_network::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::network::add_to_linker_get_host(l, &options.into(), closure)?; + crate::p2::bindings::sockets::ip_name_lookup::add_to_linker_get_host(l, closure)?; + Ok(()) +} + +/// Add all WASI interfaces from this crate into the `linker` provided. +/// +/// This function will add the synchronous variant of all interfaces into the +/// [`Linker`] provided. By synchronous this means that this function is only +/// compatible with [`Config::async_support(false)`][async]. For embeddings +/// with async support enabled see [`add_to_linker_async`] instead. +/// +/// This function will add all interfaces implemented by this crate to the +/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by +/// this crate. +/// +/// [async]: wasmtime::Config::async_support +/// +/// # Example +/// +/// ``` +/// use wasmtime::{Engine, Result, Store, Config}; +/// use wasmtime::component::{ResourceTable, Linker}; +/// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; +/// +/// fn main() -> Result<()> { +/// let engine = Engine::default(); +/// +/// let mut linker = Linker::::new(&engine); +/// wasmtime_wasi::add_to_linker_sync(&mut linker)?; +/// // ... add any further functionality to `linker` if desired ... +/// +/// let mut builder = WasiCtxBuilder::new(); +/// +/// // ... configure `builder` more to add env vars, args, etc ... +/// +/// let mut store = Store::new( +/// &engine, +/// MyState { +/// ctx: builder.build(), +/// table: ResourceTable::new(), +/// }, +/// ); +/// +/// // ... use `linker` to instantiate within `store` ... +/// +/// Ok(()) +/// } +/// +/// struct MyState { +/// ctx: WasiCtx, +/// table: ResourceTable, +/// } +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// ``` +pub fn add_to_linker_sync( + linker: &mut wasmtime::component::Linker, +) -> anyhow::Result<()> { + let options = crate::p2::bindings::sync::LinkOptions::default(); + add_to_linker_with_options_sync(linker, &options) +} + +/// Similar to [`add_to_linker_sync`], but with the ability to enable unstable features. +pub fn add_to_linker_with_options_sync( + linker: &mut wasmtime::component::Linker, + options: &crate::p2::bindings::sync::LinkOptions, +) -> anyhow::Result<()> { + let l = linker; + let io_closure = io_type_annotate::(|t| IoImpl(t)); + let closure = type_annotate::(|t| WasiImpl(IoImpl(t))); + + crate::p2::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sync::filesystem::types::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::filesystem::preopens::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::io::error::add_to_linker_get_host(l, io_closure)?; + crate::p2::bindings::sync::io::poll::add_to_linker_get_host(l, io_closure)?; + crate::p2::bindings::sync::io::streams::add_to_linker_get_host(l, io_closure)?; + crate::p2::bindings::random::random::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::random::insecure::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::random::insecure_seed::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::exit::add_to_linker_get_host(l, &options.into(), closure)?; + crate::p2::bindings::cli::environment::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::stdin::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::stdout::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::stderr::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_input::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_output::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_stdin::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_stdout::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::cli::terminal_stderr::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sync::sockets::tcp::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::tcp_create_socket::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sync::sockets::udp::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::udp_create_socket::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::instance_network::add_to_linker_get_host(l, closure)?; + crate::p2::bindings::sockets::network::add_to_linker_get_host(l, &options.into(), closure)?; + crate::p2::bindings::sockets::ip_name_lookup::add_to_linker_get_host(l, closure)?; + Ok(()) +} diff --git a/crates/wasi/wit/deps/cli/command.wit b/crates/wasi/src/p2/wit/deps/cli@v0.2.3/command.wit similarity index 100% rename from crates/wasi/wit/deps/cli/command.wit rename to crates/wasi/src/p2/wit/deps/cli@v0.2.3/command.wit diff --git a/crates/wasi/wit/deps/cli/environment.wit b/crates/wasi/src/p2/wit/deps/cli@v0.2.3/environment.wit similarity index 100% rename from crates/wasi/wit/deps/cli/environment.wit rename to crates/wasi/src/p2/wit/deps/cli@v0.2.3/environment.wit diff --git a/crates/wasi/wit/deps/cli/exit.wit b/crates/wasi/src/p2/wit/deps/cli@v0.2.3/exit.wit similarity index 100% rename from crates/wasi/wit/deps/cli/exit.wit rename to crates/wasi/src/p2/wit/deps/cli@v0.2.3/exit.wit diff --git a/crates/wasi/wit/deps/cli/imports.wit b/crates/wasi/src/p2/wit/deps/cli@v0.2.3/imports.wit similarity index 100% rename from crates/wasi/wit/deps/cli/imports.wit rename to crates/wasi/src/p2/wit/deps/cli@v0.2.3/imports.wit diff --git a/crates/wasi/wit/deps/cli/run.wit b/crates/wasi/src/p2/wit/deps/cli@v0.2.3/run.wit similarity index 100% rename from crates/wasi/wit/deps/cli/run.wit rename to crates/wasi/src/p2/wit/deps/cli@v0.2.3/run.wit diff --git a/crates/wasi/wit/deps/cli/stdio.wit b/crates/wasi/src/p2/wit/deps/cli@v0.2.3/stdio.wit similarity index 100% rename from crates/wasi/wit/deps/cli/stdio.wit rename to crates/wasi/src/p2/wit/deps/cli@v0.2.3/stdio.wit diff --git a/crates/wasi/wit/deps/cli/terminal.wit b/crates/wasi/src/p2/wit/deps/cli@v0.2.3/terminal.wit similarity index 100% rename from crates/wasi/wit/deps/cli/terminal.wit rename to crates/wasi/src/p2/wit/deps/cli@v0.2.3/terminal.wit diff --git a/crates/wasi/wit/deps/clocks/monotonic-clock.wit b/crates/wasi/src/p2/wit/deps/clocks@v0.2.3/monotonic-clock.wit similarity index 100% rename from crates/wasi/wit/deps/clocks/monotonic-clock.wit rename to crates/wasi/src/p2/wit/deps/clocks@v0.2.3/monotonic-clock.wit diff --git a/crates/wasi/wit/deps/clocks/timezone.wit b/crates/wasi/src/p2/wit/deps/clocks@v0.2.3/timezone.wit similarity index 100% rename from crates/wasi/wit/deps/clocks/timezone.wit rename to crates/wasi/src/p2/wit/deps/clocks@v0.2.3/timezone.wit diff --git a/crates/wasi/wit/deps/clocks/wall-clock.wit b/crates/wasi/src/p2/wit/deps/clocks@v0.2.3/wall-clock.wit similarity index 100% rename from crates/wasi/wit/deps/clocks/wall-clock.wit rename to crates/wasi/src/p2/wit/deps/clocks@v0.2.3/wall-clock.wit diff --git a/crates/wasi/wit/deps/clocks/world.wit b/crates/wasi/src/p2/wit/deps/clocks@v0.2.3/world.wit similarity index 100% rename from crates/wasi/wit/deps/clocks/world.wit rename to crates/wasi/src/p2/wit/deps/clocks@v0.2.3/world.wit diff --git a/crates/wasi/wit/deps/filesystem/preopens.wit b/crates/wasi/src/p2/wit/deps/filesystem@v0.2.3/preopens.wit similarity index 100% rename from crates/wasi/wit/deps/filesystem/preopens.wit rename to crates/wasi/src/p2/wit/deps/filesystem@v0.2.3/preopens.wit diff --git a/crates/wasi/wit/deps/filesystem/types.wit b/crates/wasi/src/p2/wit/deps/filesystem@v0.2.3/types.wit similarity index 100% rename from crates/wasi/wit/deps/filesystem/types.wit rename to crates/wasi/src/p2/wit/deps/filesystem@v0.2.3/types.wit diff --git a/crates/wasi/wit/deps/filesystem/world.wit b/crates/wasi/src/p2/wit/deps/filesystem@v0.2.3/world.wit similarity index 100% rename from crates/wasi/wit/deps/filesystem/world.wit rename to crates/wasi/src/p2/wit/deps/filesystem@v0.2.3/world.wit diff --git a/crates/wasi/wit/deps/io/error.wit b/crates/wasi/src/p2/wit/deps/io@v0.2.3/error.wit similarity index 100% rename from crates/wasi/wit/deps/io/error.wit rename to crates/wasi/src/p2/wit/deps/io@v0.2.3/error.wit diff --git a/crates/wasi/wit/deps/io/poll.wit b/crates/wasi/src/p2/wit/deps/io@v0.2.3/poll.wit similarity index 100% rename from crates/wasi/wit/deps/io/poll.wit rename to crates/wasi/src/p2/wit/deps/io@v0.2.3/poll.wit diff --git a/crates/wasi/wit/deps/io/streams.wit b/crates/wasi/src/p2/wit/deps/io@v0.2.3/streams.wit similarity index 100% rename from crates/wasi/wit/deps/io/streams.wit rename to crates/wasi/src/p2/wit/deps/io@v0.2.3/streams.wit diff --git a/crates/wasi/wit/deps/io/world.wit b/crates/wasi/src/p2/wit/deps/io@v0.2.3/world.wit similarity index 100% rename from crates/wasi/wit/deps/io/world.wit rename to crates/wasi/src/p2/wit/deps/io@v0.2.3/world.wit diff --git a/crates/wasi/wit/deps/random/insecure-seed.wit b/crates/wasi/src/p2/wit/deps/random@v0.2.3/insecure-seed.wit similarity index 100% rename from crates/wasi/wit/deps/random/insecure-seed.wit rename to crates/wasi/src/p2/wit/deps/random@v0.2.3/insecure-seed.wit diff --git a/crates/wasi/wit/deps/random/insecure.wit b/crates/wasi/src/p2/wit/deps/random@v0.2.3/insecure.wit similarity index 100% rename from crates/wasi/wit/deps/random/insecure.wit rename to crates/wasi/src/p2/wit/deps/random@v0.2.3/insecure.wit diff --git a/crates/wasi/wit/deps/random/random.wit b/crates/wasi/src/p2/wit/deps/random@v0.2.3/random.wit similarity index 100% rename from crates/wasi/wit/deps/random/random.wit rename to crates/wasi/src/p2/wit/deps/random@v0.2.3/random.wit diff --git a/crates/wasi/wit/deps/random/world.wit b/crates/wasi/src/p2/wit/deps/random@v0.2.3/world.wit similarity index 100% rename from crates/wasi/wit/deps/random/world.wit rename to crates/wasi/src/p2/wit/deps/random@v0.2.3/world.wit diff --git a/crates/wasi/wit/deps/sockets/instance-network.wit b/crates/wasi/src/p2/wit/deps/sockets@v0.2.3/instance-network.wit similarity index 100% rename from crates/wasi/wit/deps/sockets/instance-network.wit rename to crates/wasi/src/p2/wit/deps/sockets@v0.2.3/instance-network.wit diff --git a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi/src/p2/wit/deps/sockets@v0.2.3/ip-name-lookup.wit similarity index 100% rename from crates/wasi/wit/deps/sockets/ip-name-lookup.wit rename to crates/wasi/src/p2/wit/deps/sockets@v0.2.3/ip-name-lookup.wit diff --git a/crates/wasi/wit/deps/sockets/network.wit b/crates/wasi/src/p2/wit/deps/sockets@v0.2.3/network.wit similarity index 100% rename from crates/wasi/wit/deps/sockets/network.wit rename to crates/wasi/src/p2/wit/deps/sockets@v0.2.3/network.wit diff --git a/crates/wasi/wit/deps/sockets/tcp-create-socket.wit b/crates/wasi/src/p2/wit/deps/sockets@v0.2.3/tcp-create-socket.wit similarity index 100% rename from crates/wasi/wit/deps/sockets/tcp-create-socket.wit rename to crates/wasi/src/p2/wit/deps/sockets@v0.2.3/tcp-create-socket.wit diff --git a/crates/wasi/wit/deps/sockets/tcp.wit b/crates/wasi/src/p2/wit/deps/sockets@v0.2.3/tcp.wit similarity index 100% rename from crates/wasi/wit/deps/sockets/tcp.wit rename to crates/wasi/src/p2/wit/deps/sockets@v0.2.3/tcp.wit diff --git a/crates/wasi/wit/deps/sockets/udp-create-socket.wit b/crates/wasi/src/p2/wit/deps/sockets@v0.2.3/udp-create-socket.wit similarity index 100% rename from crates/wasi/wit/deps/sockets/udp-create-socket.wit rename to crates/wasi/src/p2/wit/deps/sockets@v0.2.3/udp-create-socket.wit diff --git a/crates/wasi/wit/deps/sockets/udp.wit b/crates/wasi/src/p2/wit/deps/sockets@v0.2.3/udp.wit similarity index 100% rename from crates/wasi/wit/deps/sockets/udp.wit rename to crates/wasi/src/p2/wit/deps/sockets@v0.2.3/udp.wit diff --git a/crates/wasi/wit/deps/sockets/world.wit b/crates/wasi/src/p2/wit/deps/sockets@v0.2.3/world.wit similarity index 100% rename from crates/wasi/wit/deps/sockets/world.wit rename to crates/wasi/src/p2/wit/deps/sockets@v0.2.3/world.wit diff --git a/crates/wasi/wit/test.wit b/crates/wasi/src/p2/wit/test.wit similarity index 100% rename from crates/wasi/wit/test.wit rename to crates/wasi/src/p2/wit/test.wit diff --git a/crates/wasi/wit/world.wit b/crates/wasi/src/p2/wit/world.wit similarity index 100% rename from crates/wasi/wit/world.wit rename to crates/wasi/src/p2/wit/world.wit diff --git a/crates/wasi/src/p3/bindings.rs b/crates/wasi/src/p3/bindings.rs new file mode 100644 index 000000000000..a19243e6aa2a --- /dev/null +++ b/crates/wasi/src/p3/bindings.rs @@ -0,0 +1,500 @@ +//! Auto-generated bindings for WASI interfaces. +//! +//! This module contains the output of the [`bindgen!`] macro when run over +//! the `wasi:cli/command` world. That means this module has all the generated +//! types for WASI for all of its base interfaces used by the CLI world. This +//! module itself by default contains bindings for `async`-related traits. The +//! [`sync`] module contains bindings for a non-`async` version of types. +//! +//! [`bindgen!`]: https://docs.rs/wasmtime/latest/wasmtime/component/macro.bindgen.html +//! +//! # Examples +//! +//! If you have a WIT world which refers to WASI interfaces you probably want to +//! use this crate's bindings rather than generate fresh bindings. That can be +//! done using the `with` option to [`bindgen!`]: +//! +//! ```rust +//! use wasmtime_wasi::{IoView, WasiCtx, ResourceTable, WasiView}; +//! use wasmtime::{Result, Engine, Config}; +//! use wasmtime::component::Linker; +//! +//! wasmtime::component::bindgen!({ +//! world: "example:wasi/my-world", +//! inline: " +//! package example:wasi; +//! +//! // An example of extending the `wasi:cli/command` world with a +//! // custom host interface. +//! world my-world { +//! include wasi:clocks/imports@0.3.0; +//! include wasi:random/imports@0.3.0; +//! +//! import custom-host; +//! } +//! +//! interface custom-host { +//! my-custom-function: func(); +//! } +//! ", +//! path: "src/p3/wit", +//! with: { +//! "wasi": wasmtime_wasi::p3::bindings, +//! }, +//! async: true, +//! }); +//! +//! struct MyState { +//! table: ResourceTable, +//! ctx: WasiCtx, +//! } +//! +//! impl example::wasi::custom_host::Host for MyState { +//! async fn my_custom_function(&mut self) { +//! // .. +//! } +//! } +//! +//! impl IoView for MyState { +//! fn table(&mut self) -> &mut ResourceTable { &mut self.table } +//! } +//! impl WasiView for MyState { +//! fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +//! } +//! +//! fn main() -> Result<()> { +//! let mut config = Config::default(); +//! config.async_support(true); +//! let engine = Engine::new(&config)?; +//! let mut linker: Linker = Linker::new(&engine); +//! wasmtime_wasi::add_to_linker_async(&mut linker)?; +//! example::wasi::custom_host::add_to_linker(&mut linker, |state| state)?; +//! +//! // .. use `Linker` to instantiate component ... +//! +//! Ok(()) +//! } +//! ``` + +/// Synchronous-generated bindings for WASI interfaces. +/// +/// This is the same as the top-level [`bindings`](crate::p3::bindings) module of +/// this crate except that it's for synchronous calls. +/// +/// # Examples +/// +/// If you have a WIT world which refers to WASI interfaces you probably want to +/// use this crate's bindings rather than generate fresh bindings. That can be +/// done using the `with` option to `bindgen!`: +/// +/// ```rust +/// use wasmtime_wasi::{IoView, WasiCtx, ResourceTable, WasiView}; +/// use wasmtime::{Result, Engine}; +/// use wasmtime::component::Linker; +/// +/// wasmtime::component::bindgen!({ +/// world: "example:wasi/my-world", +/// inline: " +/// package example:wasi; +/// +/// // An example of extending the `wasi:cli/command` world with a +/// // custom host interface. +/// world my-world { +/// include wasi:clocks/imports@0.3.0; +/// include wasi:random/imports@0.3.0; +/// +/// import custom-host; +/// } +/// +/// interface custom-host { +/// my-custom-function: func(); +/// } +/// ", +/// path: "src/p3/wit", +/// with: { +/// "wasi": wasmtime_wasi::p3::bindings::sync, +/// }, +/// // This is required for bindings using `wasmtime-wasi` and it otherwise +/// // isn't the default for non-async bindings. +/// require_store_data_send: true, +/// }); +/// +/// struct MyState { +/// table: ResourceTable, +/// ctx: WasiCtx, +/// } +/// +/// impl example::wasi::custom_host::Host for MyState { +/// fn my_custom_function(&mut self) { +/// // .. +/// } +/// } +/// +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// +/// fn main() -> Result<()> { +/// let engine = Engine::default(); +/// let mut linker: Linker = Linker::new(&engine); +/// wasmtime_wasi::add_to_linker_sync(&mut linker)?; +/// example::wasi::custom_host::add_to_linker(&mut linker, |state| state)?; +/// +/// // .. use `Linker` to instantiate component ... +/// +/// Ok(()) +/// } +/// ``` +pub mod sync { + mod generated { + wasmtime::component::bindgen!({ + path: "src/p3/wit", + // TODO: Use `command` once 0.3.0 released + //world: "wasi:cli/command", + world: "inline:wasi/command", + inline: " + package inline:wasi; + + world command { + include wasi:clocks/imports@0.3.0; + include wasi:random/imports@0.3.0; + } + ", + tracing: true, + trappable_imports: true, + with: { + // These interfaces come from the outer module, as it's + // sync/async agnostic. + "wasi:random": crate::p3::bindings::random, + "wasi:clocks/wall-clock": crate::p3::bindings::clocks::wall_clock, + }, + require_store_data_send: true, + }); + } + pub use self::generated::wasi::*; + + /// Synchronous bindings to execute and run a `wasi:cli/command`. + /// + /// This structure is automatically generated by `bindgen!` and is intended + /// to be used with [`Config::async_support(false)`][async]. For the + /// asynchronous version see [`bindings::Command`](super::Command). + /// + /// This can be used for a more "typed" view of executing a command + /// component through the [`Command::wasi_cli_run`] method plus + /// [`Guest::call_run`](exports::wasi::cli::run::Guest::call_run). + /// + /// [async]: wasmtime::Config::async_support + /// [`wasmtime_wasi::add_to_linker_sync`]: crate::add_to_linker_sync + /// + /// # Examples + /// + /// ```no_run + /// use wasmtime::{Engine, Result, Store, Config}; + /// use wasmtime::component::{ResourceTable, Linker, Component}; + /// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; + /// use wasmtime_wasi::bindings::sync::Command; + /// + /// // This example is an example shim of executing a component based on the + /// // command line arguments provided to this program. + /// fn main() -> Result<()> { + /// let args = std::env::args().skip(1).collect::>(); + /// + /// // Configure and create `Engine` + /// let engine = Engine::default(); + /// + /// // Configure a `Linker` with WASI, compile a component based on + /// // command line arguments. + /// let mut linker = Linker::::new(&engine); + /// wasmtime_wasi::add_to_linker_sync(&mut linker)?; + /// let component = Component::from_file(&engine, &args[0])?; + /// + /// + /// // Configure a `WasiCtx` based on this program's environment. Then + /// // build a `Store` to instantiate into. + /// let mut builder = WasiCtxBuilder::new(); + /// builder.inherit_stdio().inherit_env().args(&args[2..]); + /// let mut store = Store::new( + /// &engine, + /// MyState { + /// ctx: builder.build(), + /// table: ResourceTable::new(), + /// }, + /// ); + /// + /// // Instantiate the component and we're off to the races. + /// let command = Command::instantiate(&mut store, &component, &linker)?; + /// let program_result = command.wasi_cli_run().call_run(&mut store)?; + /// match program_result { + /// Ok(()) => Ok(()), + /// Err(()) => std::process::exit(1), + /// } + /// } + /// + /// struct MyState { + /// ctx: WasiCtx, + /// table: ResourceTable, + /// } + /// + /// impl IoView for MyState { + /// fn table(&mut self) -> &mut ResourceTable { &mut self.table } + /// } + /// impl WasiView for MyState { + /// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } + /// } + /// ``` + /// + /// --- + pub use self::generated::Command; + + /// Pre-instantiated analogue of [`Command`]. + /// + /// This works the same as [`Command`] but enables front-loading work such + /// as export lookup to before instantiation. + /// + /// # Examples + /// + /// ```no_run + /// use wasmtime::{Engine, Result, Store, Config}; + /// use wasmtime::component::{ResourceTable, Linker, Component}; + /// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; + /// use wasmtime_wasi::bindings::sync::CommandPre; + /// + /// // This example is an example shim of executing a component based on the + /// // command line arguments provided to this program. + /// fn main() -> Result<()> { + /// let args = std::env::args().skip(1).collect::>(); + /// + /// // Configure and create `Engine` + /// let engine = Engine::default(); + /// + /// // Configure a `Linker` with WASI, compile a component based on + /// // command line arguments, and then pre-instantiate it. + /// let mut linker = Linker::::new(&engine); + /// wasmtime_wasi::add_to_linker_sync(&mut linker)?; + /// let component = Component::from_file(&engine, &args[0])?; + /// let pre = CommandPre::new(linker.instantiate_pre(&component)?)?; + /// + /// + /// // Configure a `WasiCtx` based on this program's environment. Then + /// // build a `Store` to instantiate into. + /// let mut builder = WasiCtxBuilder::new(); + /// builder.inherit_stdio().inherit_env().args(&args); + /// let mut store = Store::new( + /// &engine, + /// MyState { + /// ctx: builder.build(), + /// table: ResourceTable::new(), + /// }, + /// ); + /// + /// // Instantiate the component and we're off to the races. + /// let command = pre.instantiate(&mut store)?; + /// let program_result = command.wasi_cli_run().call_run(&mut store)?; + /// match program_result { + /// Ok(()) => Ok(()), + /// Err(()) => std::process::exit(1), + /// } + /// } + /// + /// struct MyState { + /// ctx: WasiCtx, + /// table: ResourceTable, + /// } + /// + /// impl IoView for MyState { + /// fn table(&mut self) -> &mut ResourceTable { &mut self.table } + /// } + /// impl WasiView for MyState { + /// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } + /// } + /// ``` + /// + /// --- + pub use self::generated::CommandPre; + + pub use self::generated::CommandIndices; +} + +mod async_io { + wasmtime::component::bindgen!({ + path: "src/p3/wit", + // TODO: Use `command` once 0.3.0 released + //world: "wasi:cli/command", + world: "inline:wasi/command", + inline: " + package inline:wasi; + + world command { + include wasi:clocks/imports@0.3.0; + include wasi:random/imports@0.3.0; + } + ", + tracing: true, + trappable_imports: true, + async: { + // Only these functions are `async` and everything else is sync + // meaning that it basically doesn't need to block. These functions + // are the only ones that need to block. + // + // Note that at this time `only_imports` works on function names + // which in theory can be shared across interfaces, so this may + // need fancier syntax in the future. + only_imports: [ + "wait-for", + "wait-until", + ], + }, + }); +} + +pub use self::async_io::wasi::*; + +/// Asynchronous bindings to execute and run a `wasi:cli/command`. +/// +/// This structure is automatically generated by `bindgen!` and is intended to +/// be used with [`Config::async_support(true)`][async]. For the synchronous +/// version see [`bindings::sync::Command`](sync::Command). +/// +/// This can be used for a more "typed" view of executing a command component +/// through the [`Command::wasi_cli_run`] method plus +/// [`Guest::call_run`](exports::wasi::cli::run::Guest::call_run). +/// +/// [async]: wasmtime::Config::async_support +/// [`wasmtime_wasi::add_to_linker_async`]: crate::add_to_linker_async +/// +/// # Examples +/// +/// ```no_run +/// use wasmtime::{Engine, Result, Store, Config}; +/// use wasmtime::component::{ResourceTable, Linker, Component}; +/// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; +/// use wasmtime_wasi::bindings::Command; +/// +/// // This example is an example shim of executing a component based on the +/// // command line arguments provided to this program. +/// #[tokio::main] +/// async fn main() -> Result<()> { +/// let args = std::env::args().skip(1).collect::>(); +/// +/// // Configure and create `Engine` +/// let mut config = Config::new(); +/// config.async_support(true); +/// let engine = Engine::new(&config)?; +/// +/// // Configure a `Linker` with WASI, compile a component based on +/// // command line arguments, and then pre-instantiate it. +/// let mut linker = Linker::::new(&engine); +/// wasmtime_wasi::add_to_linker_async(&mut linker)?; +/// let component = Component::from_file(&engine, &args[0])?; +/// +/// +/// // Configure a `WasiCtx` based on this program's environment. Then +/// // build a `Store` to instantiate into. +/// let mut builder = WasiCtxBuilder::new(); +/// builder.inherit_stdio().inherit_env().args(&args); +/// let mut store = Store::new( +/// &engine, +/// MyState { +/// ctx: builder.build(), +/// table: ResourceTable::new(), +/// }, +/// ); +/// +/// // Instantiate the component and we're off to the races. +/// let command = Command::instantiate_async(&mut store, &component, &linker).await?; +/// let program_result = command.wasi_cli_run().call_run(&mut store).await?; +/// match program_result { +/// Ok(()) => Ok(()), +/// Err(()) => std::process::exit(1), +/// } +/// } +/// +/// struct MyState { +/// ctx: WasiCtx, +/// table: ResourceTable, +/// } +/// +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// ``` +/// +/// --- +pub use self::async_io::Command; + +/// Pre-instantiated analog of [`Command`] +/// +/// This can be used to front-load work such as export lookup before +/// instantiation. +/// +/// # Examples +/// +/// ```no_run +/// use wasmtime::{Engine, Result, Store, Config}; +/// use wasmtime::component::{ResourceTable, Linker, Component}; +/// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; +/// use wasmtime_wasi::bindings::CommandPre; +/// +/// // This example is an example shim of executing a component based on the +/// // command line arguments provided to this program. +/// #[tokio::main] +/// async fn main() -> Result<()> { +/// let args = std::env::args().skip(1).collect::>(); +/// +/// // Configure and create `Engine` +/// let mut config = Config::new(); +/// config.async_support(true); +/// let engine = Engine::new(&config)?; +/// +/// // Configure a `Linker` with WASI, compile a component based on +/// // command line arguments, and then pre-instantiate it. +/// let mut linker = Linker::::new(&engine); +/// wasmtime_wasi::add_to_linker_async(&mut linker)?; +/// let component = Component::from_file(&engine, &args[0])?; +/// let pre = CommandPre::new(linker.instantiate_pre(&component)?)?; +/// +/// +/// // Configure a `WasiCtx` based on this program's environment. Then +/// // build a `Store` to instantiate into. +/// let mut builder = WasiCtxBuilder::new(); +/// builder.inherit_stdio().inherit_env().args(&args); +/// let mut store = Store::new( +/// &engine, +/// MyState { +/// ctx: builder.build(), +/// table: ResourceTable::new(), +/// }, +/// ); +/// +/// // Instantiate the component and we're off to the races. +/// let command = pre.instantiate_async(&mut store).await?; +/// let program_result = command.wasi_cli_run().call_run(&mut store).await?; +/// match program_result { +/// Ok(()) => Ok(()), +/// Err(()) => std::process::exit(1), +/// } +/// } +/// +/// struct MyState { +/// ctx: WasiCtx, +/// table: ResourceTable, +/// } +/// +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// ``` +/// +/// --- +pub use self::async_io::CommandPre; + +pub use self::async_io::CommandIndices; diff --git a/crates/wasi/src/p3/host/clocks.rs b/crates/wasi/src/p3/host/clocks.rs new file mode 100644 index 000000000000..4e6f7e3d66ec --- /dev/null +++ b/crates/wasi/src/p3/host/clocks.rs @@ -0,0 +1,73 @@ +use crate::p3::bindings::{ + clocks::monotonic_clock::{self, Duration as WasiDuration, Instant}, + clocks::wall_clock::{self, Datetime}, +}; +use crate::{WasiImpl, WasiView}; +use cap_std::time::SystemTime; +use std::time::Duration; +use tokio::time::sleep; + +mod sync; + +impl TryFrom for Datetime { + type Error = anyhow::Error; + + fn try_from(time: SystemTime) -> Result { + let duration = + time.duration_since(SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH))?; + + Ok(Self { + seconds: duration.as_secs(), + nanoseconds: duration.subsec_nanos(), + }) + } +} + +impl wall_clock::Host for WasiImpl +where + T: WasiView, +{ + fn now(&mut self) -> anyhow::Result { + let now = self.ctx().wall_clock.now(); + Ok(Datetime { + seconds: now.as_secs(), + nanoseconds: now.subsec_nanos(), + }) + } + + fn resolution(&mut self) -> anyhow::Result { + let res = self.ctx().wall_clock.resolution(); + Ok(Datetime { + seconds: res.as_secs(), + nanoseconds: res.subsec_nanos(), + }) + } +} + +impl monotonic_clock::Host for WasiImpl +where + T: WasiView, +{ + fn now(&mut self) -> anyhow::Result { + Ok(self.ctx().monotonic_clock.now()) + } + + fn resolution(&mut self) -> anyhow::Result { + Ok(self.ctx().monotonic_clock.resolution()) + } + + async fn wait_until(&mut self, when: Instant) -> anyhow::Result<()> { + let clock_now = self.ctx().monotonic_clock.now(); + if when > clock_now { + sleep(Duration::from_nanos(when - clock_now)).await; + }; + Ok(()) + } + + async fn wait_for(&mut self, duration: WasiDuration) -> anyhow::Result<()> { + if duration > 0 { + sleep(Duration::from_nanos(duration)).await; + } + Ok(()) + } +} diff --git a/crates/wasi/src/p3/host/clocks/sync.rs b/crates/wasi/src/p3/host/clocks/sync.rs new file mode 100644 index 000000000000..44fb7cacf1bc --- /dev/null +++ b/crates/wasi/src/p3/host/clocks/sync.rs @@ -0,0 +1,28 @@ +use crate::p3::bindings::clocks as async_clocks; +use crate::p3::bindings::sync::clocks as sync_clocks; +use crate::p3::bindings::sync::clocks::monotonic_clock::{Duration, Instant}; +use crate::runtime::in_tokio; +use crate::{WasiImpl, WasiView}; + +impl sync_clocks::monotonic_clock::Host for WasiImpl +where + T: WasiView, +{ + fn now(&mut self) -> anyhow::Result { + async_clocks::monotonic_clock::Host::now(self) + } + + fn resolution(&mut self) -> anyhow::Result { + async_clocks::monotonic_clock::Host::resolution(self) + } + + fn wait_until(&mut self, when: Instant) -> anyhow::Result<()> { + in_tokio(async_clocks::monotonic_clock::Host::wait_until(self, when)) + } + + fn wait_for(&mut self, duration: Duration) -> anyhow::Result<()> { + in_tokio(async_clocks::monotonic_clock::Host::wait_for( + self, duration, + )) + } +} diff --git a/crates/wasi/src/p3/host/mod.rs b/crates/wasi/src/p3/host/mod.rs new file mode 100644 index 000000000000..ffe1dca5bfeb --- /dev/null +++ b/crates/wasi/src/p3/host/mod.rs @@ -0,0 +1,2 @@ +mod clocks; +mod random; diff --git a/crates/wasi/src/p3/host/random.rs b/crates/wasi/src/p3/host/random.rs new file mode 100644 index 000000000000..347da4c92edf --- /dev/null +++ b/crates/wasi/src/p3/host/random.rs @@ -0,0 +1,45 @@ +use crate::p3::bindings::random::{insecure, insecure_seed, random}; +use crate::{WasiImpl, WasiView}; +use cap_rand::{distributions::Standard, Rng}; + +impl random::Host for WasiImpl +where + T: WasiView, +{ + fn get_random_bytes(&mut self, len: u64) -> anyhow::Result> { + Ok((&mut self.ctx().random) + .sample_iter(Standard) + .take(len as usize) + .collect()) + } + + fn get_random_u64(&mut self) -> anyhow::Result { + Ok(self.ctx().random.sample(Standard)) + } +} + +impl insecure::Host for WasiImpl +where + T: WasiView, +{ + fn get_insecure_random_bytes(&mut self, len: u64) -> anyhow::Result> { + Ok((&mut self.ctx().insecure_random) + .sample_iter(Standard) + .take(len as usize) + .collect()) + } + + fn get_insecure_random_u64(&mut self) -> anyhow::Result { + Ok(self.ctx().insecure_random.sample(Standard)) + } +} + +impl insecure_seed::Host for WasiImpl +where + T: WasiView, +{ + fn insecure_seed(&mut self) -> anyhow::Result<(u64, u64)> { + let seed: u128 = self.ctx().insecure_random_seed; + Ok((seed as u64, (seed >> 64) as u64)) + } +} diff --git a/crates/wasi/src/p3/mod.rs b/crates/wasi/src/p3/mod.rs new file mode 100644 index 000000000000..60bb9766ad69 --- /dev/null +++ b/crates/wasi/src/p3/mod.rs @@ -0,0 +1,156 @@ +//! Experimental, unstable and incomplete implementation of wasip3 version of WASI. +//! +//! This module is under heavy development. +//! It is not compliant with semver and is not ready +//! for production use. +//! +//! Bug and security fixes limited to wasip3 will not be given patch releases. +//! +//! Documentation of this module may be incorrect or out-of-sync +//! with the implementation. + +use wasmtime::component::Linker; + +use crate::{type_annotate, IoImpl, WasiImpl, WasiView}; + +pub mod bindings; +pub(crate) mod host; + +/// Add all WASI interfaces from this module into the `linker` provided. +/// +/// This function will add the `async` variant of all interfaces into the +/// [`Linker`] provided. By `async` this means that this function is only +/// compatible with [`Config::async_support(true)`][async]. For embeddings with +/// async support disabled see [`add_to_linker_sync`] instead. +/// +/// This function will add all interfaces implemented by this crate to the +/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by +/// this crate. +/// +/// [async]: wasmtime::Config::async_support +/// +/// # Example +/// +/// ``` +/// use wasmtime::{Engine, Result, Store, Config}; +/// use wasmtime::component::{ResourceTable, Linker}; +/// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; +/// +/// fn main() -> Result<()> { +/// let mut config = Config::new(); +/// config.async_support(true); +/// let engine = Engine::new(&config)?; +/// +/// let mut linker = Linker::::new(&engine); +/// wasmtime_wasi::add_to_linker_async(&mut linker)?; +/// // ... add any further functionality to `linker` if desired ... +/// +/// let mut builder = WasiCtxBuilder::new(); +/// +/// // ... configure `builder` more to add env vars, args, etc ... +/// +/// let mut store = Store::new( +/// &engine, +/// MyState { +/// ctx: builder.build(), +/// table: ResourceTable::new(), +/// }, +/// ); +/// +/// // ... use `linker` to instantiate within `store` ... +/// +/// Ok(()) +/// } +/// +/// struct MyState { +/// ctx: WasiCtx, +/// table: ResourceTable, +/// } +/// +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// ``` +pub fn add_to_linker_async(linker: &mut Linker) -> anyhow::Result<()> { + let l = linker; + let closure = type_annotate::(|t| WasiImpl(IoImpl(t))); + + crate::p3::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; + crate::p3::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; + crate::p3::bindings::random::random::add_to_linker_get_host(l, closure)?; + crate::p3::bindings::random::insecure::add_to_linker_get_host(l, closure)?; + crate::p3::bindings::random::insecure_seed::add_to_linker_get_host(l, closure)?; + Ok(()) +} + +/// Add all WASI interfaces from this crate into the `linker` provided. +/// +/// This function will add the synchronous variant of all interfaces into the +/// [`Linker`] provided. By synchronous this means that this function is only +/// compatible with [`Config::async_support(false)`][async]. For embeddings +/// with async support enabled see [`add_to_linker_async`] instead. +/// +/// This function will add all interfaces implemented by this crate to the +/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by +/// this crate. +/// +/// [async]: wasmtime::Config::async_support +/// +/// # Example +/// +/// ``` +/// use wasmtime::{Engine, Result, Store, Config}; +/// use wasmtime::component::{ResourceTable, Linker}; +/// use wasmtime_wasi::{IoView, WasiCtx, WasiView, WasiCtxBuilder}; +/// +/// fn main() -> Result<()> { +/// let engine = Engine::default(); +/// +/// let mut linker = Linker::::new(&engine); +/// wasmtime_wasi::add_to_linker_sync(&mut linker)?; +/// // ... add any further functionality to `linker` if desired ... +/// +/// let mut builder = WasiCtxBuilder::new(); +/// +/// // ... configure `builder` more to add env vars, args, etc ... +/// +/// let mut store = Store::new( +/// &engine, +/// MyState { +/// ctx: builder.build(), +/// table: ResourceTable::new(), +/// }, +/// ); +/// +/// // ... use `linker` to instantiate within `store` ... +/// +/// Ok(()) +/// } +/// +/// struct MyState { +/// ctx: WasiCtx, +/// table: ResourceTable, +/// } +/// impl IoView for MyState { +/// fn table(&mut self) -> &mut ResourceTable { &mut self.table } +/// } +/// impl WasiView for MyState { +/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx } +/// } +/// ``` +pub fn add_to_linker_sync( + linker: &mut wasmtime::component::Linker, +) -> anyhow::Result<()> { + let l = linker; + let closure = type_annotate::(|t| WasiImpl(IoImpl(t))); + + crate::p3::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?; + crate::p3::bindings::sync::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?; + crate::p3::bindings::random::random::add_to_linker_get_host(l, closure)?; + crate::p3::bindings::random::insecure::add_to_linker_get_host(l, closure)?; + crate::p3::bindings::random::insecure_seed::add_to_linker_get_host(l, closure)?; + Ok(()) +} diff --git a/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/monotonic-clock.wit b/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/monotonic-clock.wit new file mode 100644 index 000000000000..87ebdaac510a --- /dev/null +++ b/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/monotonic-clock.wit @@ -0,0 +1,45 @@ +package wasi:clocks@0.3.0; +/// WASI Monotonic Clock is a clock API intended to let users measure elapsed +/// time. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +/// +/// A monotonic clock is a clock which has an unspecified initial value, and +/// successive reads of the clock will produce non-decreasing values. +@since(version = 0.3.0) +interface monotonic-clock { + /// An instant in time, in nanoseconds. An instant is relative to an + /// unspecified initial value, and can only be compared to instances from + /// the same monotonic-clock. + @since(version = 0.3.0) + type instant = u64; + + /// A duration of time, in nanoseconds. + @since(version = 0.3.0) + type duration = u64; + + /// Read the current value of the clock. + /// + /// The clock is monotonic, therefore calling this function repeatedly will + /// produce a sequence of non-decreasing values. + @since(version = 0.3.0) + now: func() -> instant; + + /// Query the resolution of the clock. Returns the duration of time + /// corresponding to a clock tick. + @since(version = 0.3.0) + resolution: func() -> duration; + + /// Wait until the specified instant has occurred. + @since(version = 0.3.0) + wait-until: func( + when: instant, + ); + + /// Wait for the specified duration has elapsed. + @since(version = 0.3.0) + wait-for: func( + how-long: duration, + ); +} diff --git a/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/timezone.wit b/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/timezone.wit new file mode 100644 index 000000000000..ac9146834f80 --- /dev/null +++ b/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/timezone.wit @@ -0,0 +1,55 @@ +package wasi:clocks@0.3.0; + +@unstable(feature = clocks-timezone) +interface timezone { + @unstable(feature = clocks-timezone) + use wall-clock.{datetime}; + + /// Return information needed to display the given `datetime`. This includes + /// the UTC offset, the time zone name, and a flag indicating whether + /// daylight saving time is active. + /// + /// If the timezone cannot be determined for the given `datetime`, return a + /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight + /// saving time. + @unstable(feature = clocks-timezone) + display: func(when: datetime) -> timezone-display; + + /// The same as `display`, but only return the UTC offset. + @unstable(feature = clocks-timezone) + utc-offset: func(when: datetime) -> s32; + + /// Information useful for displaying the timezone of a specific `datetime`. + /// + /// This information may vary within a single `timezone` to reflect daylight + /// saving time adjustments. + @unstable(feature = clocks-timezone) + record timezone-display { + /// The number of seconds difference between UTC time and the local + /// time of the timezone. + /// + /// The returned value will always be less than 86400 which is the + /// number of seconds in a day (24*60*60). + /// + /// In implementations that do not expose an actual time zone, this + /// should return 0. + utc-offset: s32, + + /// The abbreviated name of the timezone to display to a user. The name + /// `UTC` indicates Coordinated Universal Time. Otherwise, this should + /// reference local standards for the name of the time zone. + /// + /// In implementations that do not expose an actual time zone, this + /// should be the string `UTC`. + /// + /// In time zones that do not have an applicable name, a formatted + /// representation of the UTC offset may be returned, such as `-04:00`. + name: string, + + /// Whether daylight saving time is active. + /// + /// In implementations that do not expose an actual time zone, this + /// should return false. + in-daylight-saving-time: bool, + } +} diff --git a/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/wall-clock.wit b/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/wall-clock.wit new file mode 100644 index 000000000000..b7a85ab35636 --- /dev/null +++ b/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/wall-clock.wit @@ -0,0 +1,46 @@ +package wasi:clocks@0.3.0; +/// WASI Wall Clock is a clock API intended to let users query the current +/// time. The name "wall" makes an analogy to a "clock on the wall", which +/// is not necessarily monotonic as it may be reset. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +/// +/// A wall clock is a clock which measures the date and time according to +/// some external reference. +/// +/// External references may be reset, so this clock is not necessarily +/// monotonic, making it unsuitable for measuring elapsed time. +/// +/// It is intended for reporting the current date and time for humans. +@since(version = 0.3.0) +interface wall-clock { + /// A time and date in seconds plus nanoseconds. + @since(version = 0.3.0) + record datetime { + seconds: u64, + nanoseconds: u32, + } + + /// Read the current value of the clock. + /// + /// This clock is not monotonic, therefore calling this function repeatedly + /// will not necessarily produce a sequence of non-decreasing values. + /// + /// The returned timestamps represent the number of seconds since + /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], + /// also known as [Unix Time]. + /// + /// The nanoseconds field of the output is always less than 1000000000. + /// + /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 + /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time + @since(version = 0.3.0) + now: func() -> datetime; + + /// Query the resolution of the clock. + /// + /// The nanoseconds field of the output is always less than 1000000000. + @since(version = 0.3.0) + resolution: func() -> datetime; +} diff --git a/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/world.wit b/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/world.wit new file mode 100644 index 000000000000..f97bcfef13b2 --- /dev/null +++ b/crates/wasi/src/p3/wit/deps/clocks@3850f9d@wit-0.3.0-draft/world.wit @@ -0,0 +1,11 @@ +package wasi:clocks@0.3.0; + +@since(version = 0.3.0) +world imports { + @since(version = 0.3.0) + import monotonic-clock; + @since(version = 0.3.0) + import wall-clock; + @unstable(feature = clocks-timezone) + import timezone; +} diff --git a/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/insecure-seed.wit b/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/insecure-seed.wit new file mode 100644 index 000000000000..4708d9049359 --- /dev/null +++ b/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/insecure-seed.wit @@ -0,0 +1,27 @@ +package wasi:random@0.3.0; +/// The insecure-seed interface for seeding hash-map DoS resistance. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +@since(version = 0.3.0) +interface insecure-seed { + /// Return a 128-bit value that may contain a pseudo-random value. + /// + /// The returned value is not required to be computed from a CSPRNG, and may + /// even be entirely deterministic. Host implementations are encouraged to + /// provide pseudo-random values to any program exposed to + /// attacker-controlled content, to enable DoS protection built into many + /// languages' hash-map implementations. + /// + /// This function is intended to only be called once, by a source language + /// to initialize Denial Of Service (DoS) protection in its hash-map + /// implementation. + /// + /// # Expected future evolution + /// + /// This will likely be changed to a value import, to prevent it from being + /// called multiple times and potentially used for purposes other than DoS + /// protection. + @since(version = 0.3.0) + insecure-seed: func() -> tuple; +} diff --git a/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/insecure.wit b/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/insecure.wit new file mode 100644 index 000000000000..4ea5e581fd2d --- /dev/null +++ b/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/insecure.wit @@ -0,0 +1,25 @@ +package wasi:random@0.3.0; +/// The insecure interface for insecure pseudo-random numbers. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +@since(version = 0.3.0) +interface insecure { + /// Return `len` insecure pseudo-random bytes. + /// + /// This function is not cryptographically secure. Do not use it for + /// anything related to security. + /// + /// There are no requirements on the values of the returned bytes, however + /// implementations are encouraged to return evenly distributed values with + /// a long period. + @since(version = 0.3.0) + get-insecure-random-bytes: func(len: u64) -> list; + + /// Return an insecure pseudo-random `u64` value. + /// + /// This function returns the same type of pseudo-random data as + /// `get-insecure-random-bytes`, represented as a `u64`. + @since(version = 0.3.0) + get-insecure-random-u64: func() -> u64; +} diff --git a/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/random.wit b/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/random.wit new file mode 100644 index 000000000000..786ef25f68cf --- /dev/null +++ b/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/random.wit @@ -0,0 +1,29 @@ +package wasi:random@0.3.0; +/// WASI Random is a random data API. +/// +/// It is intended to be portable at least between Unix-family platforms and +/// Windows. +@since(version = 0.3.0) +interface random { + /// Return `len` cryptographically-secure random or pseudo-random bytes. + /// + /// This function must produce data at least as cryptographically secure and + /// fast as an adequately seeded cryptographically-secure pseudo-random + /// number generator (CSPRNG). It must not block, from the perspective of + /// the calling program, under any circumstances, including on the first + /// request and on requests for numbers of bytes. The returned data must + /// always be unpredictable. + /// + /// This function must always return fresh data. Deterministic environments + /// must omit this function, rather than implementing it with deterministic + /// data. + @since(version = 0.3.0) + get-random-bytes: func(len: u64) -> list; + + /// Return a cryptographically-secure random or pseudo-random `u64` value. + /// + /// This function returns the same type of data as `get-random-bytes`, + /// represented as a `u64`. + @since(version = 0.3.0) + get-random-u64: func() -> u64; +} diff --git a/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/world.wit b/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/world.wit new file mode 100644 index 000000000000..838d38023cfe --- /dev/null +++ b/crates/wasi/src/p3/wit/deps/random@3e99124@wit-0.3.0-draft/world.wit @@ -0,0 +1,13 @@ +package wasi:random@0.3.0; + +@since(version = 0.3.0) +world imports { + @since(version = 0.3.0) + import random; + + @since(version = 0.3.0) + import insecure; + + @since(version = 0.3.0) + import insecure-seed; +} diff --git a/crates/wasi/src/p3/wit/world.wit b/crates/wasi/src/p3/wit/world.wit new file mode 100644 index 000000000000..b1811df73379 --- /dev/null +++ b/crates/wasi/src/p3/wit/world.wit @@ -0,0 +1,11 @@ +// We actually don't use this; it's just to let bindgen! find the corresponding world in wit/deps. + +package wasmtime:wasi; + +world bindings { + // TODO: Replace explicit includes by `wasi:cli/command@0.3.0` once released + //include wasi:cli/imports@0.3.0; + + include wasi:clocks/imports@0.3.0; + include wasi:random/imports@0.3.0; +} diff --git a/crates/wasi/src/poll.rs b/crates/wasi/src/poll.rs index 0d774b9b5e30..dfac369026cf 100644 --- a/crates/wasi/src/poll.rs +++ b/crates/wasi/src/poll.rs @@ -177,7 +177,7 @@ where } } -impl crate::bindings::io::poll::HostPollable for IoImpl +impl crate::p2::bindings::io::poll::HostPollable for IoImpl where T: IoView, { @@ -226,7 +226,7 @@ pub mod sync { } } - impl crate::bindings::sync::io::poll::HostPollable for IoImpl + impl crate::p2::bindings::sync::io::poll::HostPollable for IoImpl where T: IoView, { diff --git a/crates/wasi/src/preview1.rs b/crates/wasi/src/preview1.rs index 838875d11342..531b7ed960b8 100644 --- a/crates/wasi/src/preview1.rs +++ b/crates/wasi/src/preview1.rs @@ -63,7 +63,7 @@ //! } //! ``` -use crate::bindings::{ +use crate::p2::bindings::{ cli::{ stderr::Host as _, stdin::Host as _, stdout::Host as _, terminal_input, terminal_output, terminal_stderr::Host as _, terminal_stdin::Host as _, terminal_stdout::Host as _, @@ -89,10 +89,10 @@ use wiggle::tracing::instrument; use wiggle::{GuestError, GuestMemory, GuestPtr, GuestType}; // Bring all WASI traits in scope that this implementation builds on. -use crate::bindings::cli::environment::Host as _; -use crate::bindings::filesystem::types::HostDescriptor as _; -use crate::bindings::io::poll::Host as _; -use crate::bindings::random::random::Host as _; +use crate::p2::bindings::cli::environment::Host as _; +use crate::p2::bindings::filesystem::types::HostDescriptor as _; +use crate::p2::bindings::io::poll::Host as _; +use crate::p2::bindings::random::random::Host as _; /// Structure containing state for WASIp1. /// diff --git a/crates/wasi/src/stdio.rs b/crates/wasi/src/stdio.rs index 17ab5820db73..fc903483d210 100644 --- a/crates/wasi/src/stdio.rs +++ b/crates/wasi/src/stdio.rs @@ -1,8 +1,8 @@ -use crate::bindings::cli::{ +use crate::p2::bindings::cli::{ stderr, stdin, stdout, terminal_input, terminal_output, terminal_stderr, terminal_stdin, terminal_stdout, }; -use crate::bindings::io::streams; +use crate::p2::bindings::io::streams; use crate::pipe; use crate::{ HostInputStream, HostOutputStream, IoView, StreamError, StreamResult, Subscribe, WasiImpl, diff --git a/crates/wasi/src/tcp.rs b/crates/wasi/src/tcp.rs index 5b05ebb25339..75cc8c39d0bc 100644 --- a/crates/wasi/src/tcp.rs +++ b/crates/wasi/src/tcp.rs @@ -1,6 +1,6 @@ -use crate::bindings::sockets::tcp::ErrorCode; use crate::host::network; use crate::network::SocketAddressFamily; +use crate::p2::bindings::sockets::tcp::ErrorCode; use crate::runtime::{with_ambient_tokio_runtime, AbortOnDropJoinHandle}; use crate::{ HostInputStream, HostOutputStream, InputStream, OutputStream, SocketError, SocketResult, @@ -146,7 +146,7 @@ impl TcpSocket { } fn as_std_view(&self) -> SocketResult> { - use crate::bindings::sockets::network::ErrorCode; + use crate::p2::bindings::sockets::network::ErrorCode; match &self.tcp_state { TcpState::Default(socket) | TcpState::Bound(socket) => { diff --git a/crates/wasi/src/udp.rs b/crates/wasi/src/udp.rs index 1e0b1a199cf4..a4f67310a2b2 100644 --- a/crates/wasi/src/udp.rs +++ b/crates/wasi/src/udp.rs @@ -1,4 +1,4 @@ -use crate::host::network::util; +use crate::p2::host::network::util; use crate::poll::Subscribe; use crate::runtime::with_ambient_tokio_runtime; use async_trait::async_trait; diff --git a/crates/wasi/src/view.rs b/crates/wasi/src/view.rs index 58375b1b60ab..bf7ce109edb6 100644 --- a/crates/wasi/src/view.rs +++ b/crates/wasi/src/view.rs @@ -13,7 +13,7 @@ pub trait IoView: Send { pub trait WasiView: IoView { /// Yields mutable access to the configuration used for this context. /// - /// The returned type is created through [`WasiCtxBuilder`]. + /// The returned type is created through [`WasiCtxBuilder`](crate::WasiCtxBuilder). fn ctx(&mut self) -> &mut WasiCtx; } @@ -49,7 +49,7 @@ impl WasiView for Box { /// /// This type is otherwise provided if you're calling the `add_to_linker` /// functions generated by `bindgen!` from the [`bindings` -/// module](crate::bindings). In this situation you'll want to create a value of +/// module](crate::p2::bindings). In this situation you'll want to create a value of /// this type in the closures added to a `Linker`. #[repr(transparent)] pub struct IoImpl(pub T); @@ -69,7 +69,7 @@ impl IoView for IoImpl { /// /// This type is otherwise provided if you're calling the `add_to_linker` /// functions generated by `bindgen!` from the [`bindings` -/// module](crate::bindings). In this situation you'll want to create a value of +/// module](crate::p2::bindings). In this situation you'll want to create a value of /// this type in the closures added to a `Linker`. #[repr(transparent)] pub struct WasiImpl(pub IoImpl); diff --git a/crates/wasi/tests/all/api.rs b/crates/wasi/tests/all/api.rs index ca5219988744..ebd315288351 100644 --- a/crates/wasi/tests/all/api.rs +++ b/crates/wasi/tests/all/api.rs @@ -6,10 +6,9 @@ use std::sync::Mutex; use std::time::Duration; use wasmtime::component::{Component, Linker, ResourceTable}; use wasmtime::Store; -use wasmtime_wasi::bindings::Command; use wasmtime_wasi::{ add_to_linker_async, - bindings::{clocks::wall_clock, filesystem::types as filesystem}, + p2::bindings::{clocks::wall_clock, filesystem::types as filesystem, Command}, DirPerms, FilePerms, HostMonotonicClock, HostWallClock, IoView, WasiCtx, WasiCtxBuilder, WasiView, }; @@ -132,8 +131,9 @@ fn api_proxy_forward_request() {} wasmtime::component::bindgen!({ world: "test-reactor", + path: "src/p2/wit", async: true, - with: { "wasi": wasmtime_wasi::bindings }, + with: { "wasi": wasmtime_wasi::p2::bindings }, ownership: Borrowing { duplicate_if_necessary: false } diff --git a/crates/wasi/tests/all/async_.rs b/crates/wasi/tests/all/async_.rs index 7d25423726b2..18b971a4aa7d 100644 --- a/crates/wasi/tests/all/async_.rs +++ b/crates/wasi/tests/all/async_.rs @@ -1,8 +1,7 @@ use super::*; use std::path::Path; use test_programs_artifacts::*; -use wasmtime_wasi::add_to_linker_async; -use wasmtime_wasi::bindings::Command; +use wasmtime_wasi::p2::bindings::Command; async fn run(path: &str, inherit_stdio: bool) -> Result<()> { let path = Path::new(path); @@ -11,7 +10,10 @@ async fn run(path: &str, inherit_stdio: bool) -> Result<()> { config.async_support(true); }); let mut linker = Linker::new(&engine); - add_to_linker_async(&mut linker)?; + wasmtime_wasi::p2::add_to_linker_async(&mut linker)?; + + #[cfg(feature = "p3")] + wasmtime_wasi::p3::add_to_linker_sync(&mut linker)?; let (mut store, _td) = store(&engine, name, |builder| { if inherit_stdio { @@ -30,6 +32,9 @@ async fn run(path: &str, inherit_stdio: bool) -> Result<()> { foreach_preview1!(assert_test_exists); foreach_preview2!(assert_test_exists); +#[cfg(feature = "p3")] +foreach_preview3!(assert_test_exists); + // Below here is mechanical: there should be one test for every binary in // wasi-tests. #[test_log::test(tokio::test(flavor = "multi_thread"))] @@ -399,3 +404,14 @@ async fn preview2_file_read_write() { .await .unwrap() } + +#[cfg(feature = "p3")] +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn preview3_sleep() { + run(PREVIEW3_SLEEP_COMPONENT, false).await.unwrap() +} +#[cfg(feature = "p3")] +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn preview3_random() { + run(PREVIEW3_RANDOM_COMPONENT, false).await.unwrap() +} diff --git a/crates/wasi/tests/all/sync.rs b/crates/wasi/tests/all/sync.rs index 5629d5d3ffd8..5e1584f15e4b 100644 --- a/crates/wasi/tests/all/sync.rs +++ b/crates/wasi/tests/all/sync.rs @@ -1,15 +1,16 @@ use super::*; use std::path::Path; use test_programs_artifacts::*; -use wasmtime_wasi::add_to_linker_sync; -use wasmtime_wasi::bindings::sync::Command; +use wasmtime_wasi::p2::bindings::sync::Command; fn run(path: &str, inherit_stdio: bool) -> Result<()> { let path = Path::new(path); let name = path.file_stem().unwrap().to_str().unwrap(); let engine = test_programs_artifacts::engine(|_| {}); let mut linker = Linker::new(&engine); - add_to_linker_sync(&mut linker)?; + wasmtime_wasi::p2::add_to_linker_sync(&mut linker)?; + #[cfg(feature = "p3")] + wasmtime_wasi::p3::add_to_linker_sync(&mut linker)?; let component = Component::from_file(&engine, path)?; @@ -32,6 +33,9 @@ fn run(path: &str, inherit_stdio: bool) -> Result<()> { foreach_preview1!(assert_test_exists); foreach_preview2!(assert_test_exists); +#[cfg(feature = "p3")] +foreach_preview3!(assert_test_exists); + // Below here is mechanical: there should be one test for every binary in // wasi-tests. #[test_log::test] @@ -333,3 +337,14 @@ fn preview2_adapter_badfd() { fn preview2_file_read_write() { run(PREVIEW2_FILE_READ_WRITE_COMPONENT, false).unwrap() } + +#[cfg(feature = "p3")] +#[test_log::test] +fn preview3_sleep() { + run(PREVIEW3_SLEEP_COMPONENT, false).unwrap() +} +#[cfg(feature = "p3")] +#[test_log::test] +fn preview3_random() { + run(PREVIEW3_RANDOM_COMPONENT, false).unwrap() +} diff --git a/crates/wasmtime/src/runtime/component/mod.rs b/crates/wasmtime/src/runtime/component/mod.rs index 5c347102903a..9cc609b06a1c 100644 --- a/crates/wasmtime/src/runtime/component/mod.rs +++ b/crates/wasmtime/src/runtime/component/mod.rs @@ -345,13 +345,13 @@ pub(crate) use self::store::ComponentStoreData; /// // This can be used to indicate that entire interfaces have /// // bindings generated elsewhere with a path pointing to the /// // bindinges-generated module. -/// "wasi:random/random": wasmtime_wasi::bindings::random::random, +/// "wasi:random/random": wasmtime_wasi::p2::bindings::random::random, /// /// // Similarly entire packages can also be specified. -/// "wasi:cli": wasmtime_wasi::bindings::cli, +/// "wasi:cli": wasmtime_wasi::p2::bindings::cli, /// /// // Or, if applicable, entire namespaces can additionally be mapped. -/// "wasi": wasmtime_wasi::bindings, +/// "wasi": wasmtime_wasi::p2::bindings, /// /// // Versions are supported if multiple versions are in play: /// "wasi:http/types@0.2.0": wasmtime_wasi_http::bindings::http::types,