diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cbc54e1109..d0474189ce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -223,7 +223,7 @@ jobs: echo "${{ runner.tool_cache }}/mdbook/bin" >> $GITHUB_PATH cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.CARGO_MDBOOK_VERSION }} mdbook - run: (cd docs && mdbook build) - - run: cargo build -p wasmtime-wasi --features wasmtime/wat,wasmtime/cranelift + - run: cargo build -p wasi-common --features wasmtime/wat,wasmtime/cranelift - run: (cd docs/rust_wasi_markdown_parser && cargo build) - run: (cd docs && mdbook test -L ../target/debug/deps) diff --git a/Cargo.lock b/Cargo.lock index 11113a9ca6..15974af9b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3326,7 +3326,6 @@ dependencies = [ "wasi-common", "wasmtime", "wasmtime-c-api-macros", - "wasmtime-wasi", "wat", ] @@ -3695,12 +3694,10 @@ dependencies = [ "cap-rand", "cap-std", "cap-time-ext", - "cfg-if", "fs-set-times", "futures", "io-extras", "io-lifetimes", - "log", "once_cell", "rustix", "system-interface", @@ -3712,7 +3709,6 @@ dependencies = [ "tracing", "tracing-subscriber", "url", - "wasi-common", "wasmtime", "wiggle", "windows-sys 0.52.0", diff --git a/Cargo.toml b/Cargo.toml index b6b88a7596..19779cddde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,7 @@ wasmtime-wast = { workspace = true, optional = true } wasi-common = { workspace = true, default-features = true, features = [ "exit", ] } -wasmtime-wasi = { workspace = true, default-features = true, features = [ - "exit", -] } +wasmtime-wasi = { workspace = true, default-features = true } wasmtime-wasi-nn = { workspace = true, optional = true } wasmtime-wasi-threads = { workspace = true, optional = true } wasmtime-wasi-http = { workspace = true, optional = true } @@ -394,7 +392,7 @@ harness = false [[example]] name = "tokio" -required-features = ["wasmtime-wasi/tokio"] +required-features = ["wasi-common/tokio"] [[bench]] name = "instantiation" diff --git a/crates/c-api/Cargo.toml b/crates/c-api/Cargo.toml index 2ae1d175ef..6b470b15c0 100644 --- a/crates/c-api/Cargo.toml +++ b/crates/c-api/Cargo.toml @@ -31,7 +31,6 @@ tracing = { workspace = true } wat = { workspace = true, optional = true } # Optional dependencies for the `wasi` feature -wasmtime-wasi = { workspace = true, default-features = true, optional = true } cap-std = { workspace = true, optional = true } wasi-common = { workspace = true, optional = true, features = ["sync"] } @@ -43,7 +42,7 @@ async = ['wasmtime/async', 'futures'] profiling = ["wasmtime/profiling"] cache = ["wasmtime/cache"] parallel-compilation = ['wasmtime/parallel-compilation'] -wasi = ['wasmtime-wasi', 'cap-std', 'wasi-common'] +wasi = ['cap-std', 'wasi-common'] logging = ['dep:env_logger'] disable-logging = ["log/max_level_off", "tracing/max_level_off"] coredump = ["wasmtime/coredump"] diff --git a/crates/c-api/src/linker.rs b/crates/c-api/src/linker.rs index 6ea36fa053..4ef4aaecf6 100644 --- a/crates/c-api/src/linker.rs +++ b/crates/c-api/src/linker.rs @@ -104,7 +104,7 @@ pub extern "C" fn wasmtime_linker_define_wasi( linker: &mut wasmtime_linker_t, ) -> Option> { handle_result( - wasmtime_wasi::add_to_linker(&mut linker.linker, |cx| { + wasi_common::sync::add_to_linker(&mut linker.linker, |cx| { cx.wasi.as_mut().expect( "failed to define WASI on linker; did you set a WASI configuration in the store?", ) diff --git a/crates/wasi-http/Cargo.toml b/crates/wasi-http/Cargo.toml index 996d8c8aa8..cd9c097ce2 100644 --- a/crates/wasi-http/Cargo.toml +++ b/crates/wasi-http/Cargo.toml @@ -25,9 +25,7 @@ http = { workspace = true } http-body = { workspace = true } http-body-util = { workspace = true } tracing = { workspace = true } -wasmtime-wasi = { workspace = true, default-features = false, features = [ - "preview2", -] } +wasmtime-wasi = { workspace = true } wasmtime = { workspace = true, features = ['component-model'] } # The `ring` crate, used to implement TLS, does not build on riscv64 or s390x diff --git a/crates/wasi-http/src/body.rs b/crates/wasi-http/src/body.rs index 92e73d4205..e693de64df 100644 --- a/crates/wasi-http/src/body.rs +++ b/crates/wasi-http/src/body.rs @@ -9,7 +9,7 @@ use std::mem; use std::task::{Context, Poll}; use std::{pin::Pin, sync::Arc, time::Duration}; use tokio::sync::{mpsc, oneshot}; -use wasmtime_wasi::preview2::{ +use wasmtime_wasi::{ self, poll_noop, AbortOnDropJoinHandle, HostInputStream, HostOutputStream, StreamError, Subscribe, }; @@ -36,7 +36,7 @@ impl BodyWithTimeout { inner, between_bytes_timeout, reset_sleep: true, - timeout: Box::pin(preview2::with_ambient_tokio_runtime(|| { + timeout: Box::pin(wasmtime_wasi::with_ambient_tokio_runtime(|| { tokio::time::sleep(Duration::new(0, 0)) })), } diff --git a/crates/wasi-http/src/lib.rs b/crates/wasi-http/src/lib.rs index e7218250a2..7a78d6f64d 100644 --- a/crates/wasi-http/src/lib.rs +++ b/crates/wasi-http/src/lib.rs @@ -18,9 +18,9 @@ pub mod bindings { tracing: true, async: false, with: { - "wasi:io/error": wasmtime_wasi::preview2::bindings::io::error, - "wasi:io/streams": wasmtime_wasi::preview2::bindings::io::streams, - "wasi:io/poll": wasmtime_wasi::preview2::bindings::io::poll, + "wasi:io/error": wasmtime_wasi::bindings::io::error, + "wasi:io/streams": wasmtime_wasi::bindings::io::streams, + "wasi:io/poll": wasmtime_wasi::bindings::io::poll, "wasi:http/types/outgoing-body": super::body::HostOutgoingBody, "wasi:http/types/future-incoming-response": super::types::HostFutureIncomingResponse, diff --git a/crates/wasi-http/src/proxy.rs b/crates/wasi-http/src/proxy.rs index 5c65576788..c59816860e 100644 --- a/crates/wasi-http/src/proxy.rs +++ b/crates/wasi-http/src/proxy.rs @@ -1,39 +1,38 @@ use crate::{bindings, WasiHttpView}; -use wasmtime_wasi::preview2; wasmtime::component::bindgen!({ world: "wasi:http/proxy", tracing: true, async: true, with: { - "wasi:cli/stderr": preview2::bindings::cli::stderr, - "wasi:cli/stdin": preview2::bindings::cli::stdin, - "wasi:cli/stdout": preview2::bindings::cli::stdout, - "wasi:clocks/monotonic-clock": preview2::bindings::clocks::monotonic_clock, - "wasi:clocks/timezone": preview2::bindings::clocks::timezone, - "wasi:clocks/wall-clock": preview2::bindings::clocks::wall_clock, + "wasi:cli/stderr": wasmtime_wasi::bindings::cli::stderr, + "wasi:cli/stdin": wasmtime_wasi::bindings::cli::stdin, + "wasi:cli/stdout": wasmtime_wasi::bindings::cli::stdout, + "wasi:clocks/monotonic-clock": wasmtime_wasi::bindings::clocks::monotonic_clock, + "wasi:clocks/timezone": wasmtime_wasi::bindings::clocks::timezone, + "wasi:clocks/wall-clock": wasmtime_wasi::bindings::clocks::wall_clock, "wasi:http/incoming-handler": bindings::http::incoming_handler, "wasi:http/outgoing-handler": bindings::http::outgoing_handler, "wasi:http/types": bindings::http::types, - "wasi:io/streams": preview2::bindings::io::streams, - "wasi:io/poll": preview2::bindings::io::poll, - "wasi:random/random": preview2::bindings::random::random, + "wasi:io/streams": wasmtime_wasi::bindings::io::streams, + "wasi:io/poll": wasmtime_wasi::bindings::io::poll, + "wasi:random/random": wasmtime_wasi::bindings::random::random, }, }); pub fn add_to_linker(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> where - T: WasiHttpView + preview2::WasiView + bindings::http::types::Host, + T: WasiHttpView + wasmtime_wasi::WasiView + bindings::http::types::Host, { - preview2::bindings::clocks::wall_clock::add_to_linker(l, |t| t)?; - preview2::bindings::clocks::monotonic_clock::add_to_linker(l, |t| t)?; - preview2::bindings::io::poll::add_to_linker(l, |t| t)?; - preview2::bindings::io::error::add_to_linker(l, |t| t)?; - preview2::bindings::io::streams::add_to_linker(l, |t| t)?; - preview2::bindings::cli::stdin::add_to_linker(l, |t| t)?; - preview2::bindings::cli::stdout::add_to_linker(l, |t| t)?; - preview2::bindings::cli::stderr::add_to_linker(l, |t| t)?; - preview2::bindings::random::random::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::clocks::wall_clock::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::clocks::monotonic_clock::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::io::poll::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::io::error::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::io::streams::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::cli::stdin::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::cli::stdout::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::cli::stderr::add_to_linker(l, |t| t)?; + wasmtime_wasi::bindings::random::random::add_to_linker(l, |t| t)?; add_only_http_to_linker(l) } @@ -41,7 +40,7 @@ where #[doc(hidden)] pub fn add_only_http_to_linker(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> where - T: WasiHttpView + preview2::WasiView + bindings::http::types::Host, + T: WasiHttpView + wasmtime_wasi::WasiView + bindings::http::types::Host, { bindings::http::outgoing_handler::add_to_linker(l, |t| t)?; bindings::http::types::add_to_linker(l, |t| t)?; @@ -51,35 +50,35 @@ where pub mod sync { use crate::{bindings, WasiHttpView}; - use wasmtime_wasi::preview2; + use wasmtime_wasi; wasmtime::component::bindgen!({ world: "wasi:http/proxy", tracing: true, async: false, with: { - "wasi:cli/stderr": preview2::bindings::cli::stderr, - "wasi:cli/stdin": preview2::bindings::cli::stdin, - "wasi:cli/stdout": preview2::bindings::cli::stdout, - "wasi:clocks/monotonic-clock": preview2::bindings::clocks::monotonic_clock, - "wasi:clocks/timezone": preview2::bindings::clocks::timezone, - "wasi:clocks/wall-clock": preview2::bindings::clocks::wall_clock, + "wasi:cli/stderr": wasmtime_wasi::bindings::cli::stderr, + "wasi:cli/stdin": wasmtime_wasi::bindings::cli::stdin, + "wasi:cli/stdout": wasmtime_wasi::bindings::cli::stdout, + "wasi:clocks/monotonic-clock": wasmtime_wasi::bindings::clocks::monotonic_clock, + "wasi:clocks/timezone": wasmtime_wasi::bindings::clocks::timezone, + "wasi:clocks/wall-clock": wasmtime_wasi::bindings::clocks::wall_clock, "wasi:http/incoming-handler": bindings::http::incoming_handler, "wasi:http/outgoing-handler": bindings::http::outgoing_handler, "wasi:http/types": bindings::http::types, - "wasi:io/streams": preview2::bindings::io::streams, - "wasi:poll/poll": preview2::bindings::poll::poll, - "wasi:random/random": preview2::bindings::random::random, + "wasi:io/streams": wasmtime_wasi::bindings::io::streams, + "wasi:poll/poll": wasmtime_wasi::bindings::poll::poll, + "wasi:random/random": wasmtime_wasi::bindings::random::random, }, }); pub fn add_to_linker(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> where - T: WasiHttpView + preview2::WasiView + bindings::http::types::Host, + T: WasiHttpView + wasmtime_wasi::WasiView + bindings::http::types::Host, { // TODO: this shouldn't be required, but the adapter unconditionally pulls in all of these // dependencies. - preview2::command::sync::add_to_linker(l)?; + wasmtime_wasi::command::sync::add_to_linker(l)?; add_only_http_to_linker(l)?; @@ -87,10 +86,10 @@ pub mod sync { } #[doc(hidden)] - // TODO: This is temporary solution until the preview2 command functions can be removed + // TODO: This is temporary solution until the wasmtime_wasi command functions can be removed pub fn add_only_http_to_linker(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> where - T: WasiHttpView + preview2::WasiView + bindings::http::types::Host, + T: WasiHttpView + wasmtime_wasi::WasiView + bindings::http::types::Host, { bindings::http::outgoing_handler::add_to_linker(l, |t| t)?; bindings::http::types::add_to_linker(l, |t| t)?; diff --git a/crates/wasi-http/src/types.rs b/crates/wasi-http/src/types.rs index 3d8c4ef225..a51709dc53 100644 --- a/crates/wasi-http/src/types.rs +++ b/crates/wasi-http/src/types.rs @@ -15,7 +15,7 @@ use std::time::Duration; use tokio::net::TcpStream; use tokio::time::timeout; use wasmtime::component::{Resource, ResourceTable}; -use wasmtime_wasi::preview2::{self, AbortOnDropJoinHandle, Subscribe}; +use wasmtime_wasi::{self, AbortOnDropJoinHandle, Subscribe}; /// Capture the state necessary for use in the wasi-http API implementation. pub struct WasiHttpCtx; @@ -122,7 +122,7 @@ pub fn default_send_request( between_bytes_timeout, }: OutgoingRequest, ) -> wasmtime::Result> { - let handle = preview2::spawn(async move { + let handle = wasmtime_wasi::spawn(async move { let resp = handler( authority, use_tls, @@ -212,7 +212,7 @@ async fn handler( .map_err(|_| types::ErrorCode::ConnectionTimeout)? .map_err(hyper_request_error)?; - let worker = preview2::spawn(async move { + let worker = wasmtime_wasi::spawn(async move { match conn.await { Ok(()) => {} // TODO: shouldn't throw away this error and ideally should @@ -234,7 +234,7 @@ async fn handler( .map_err(|_| types::ErrorCode::ConnectionTimeout)? .map_err(hyper_request_error)?; - let worker = preview2::spawn(async move { + let worker = wasmtime_wasi::spawn(async move { match conn.await { Ok(()) => {} // TODO: same as above, shouldn't throw this error away. diff --git a/crates/wasi-http/src/types_impl.rs b/crates/wasi-http/src/types_impl.rs index 351f8f59d7..07ef93a329 100644 --- a/crates/wasi-http/src/types_impl.rs +++ b/crates/wasi-http/src/types_impl.rs @@ -12,7 +12,7 @@ use anyhow::Context; use std::any::Any; use std::str::FromStr; use wasmtime::component::{Resource, ResourceTable}; -use wasmtime_wasi::preview2::{ +use wasmtime_wasi::{ bindings::io::streams::{InputStream, OutputStream}, Pollable, }; @@ -644,7 +644,7 @@ impl crate::bindings::http::types::HostFutureTrailers for T { &mut self, index: Resource, ) -> wasmtime::Result> { - wasmtime_wasi::preview2::subscribe(self.table(), index) + wasmtime_wasi::subscribe(self.table(), index) } fn get( @@ -852,7 +852,7 @@ impl crate::bindings::http::types::HostFutureIncomingResponse f &mut self, id: Resource, ) -> wasmtime::Result> { - wasmtime_wasi::preview2::subscribe(self.table(), id) + wasmtime_wasi::subscribe(self.table(), id) } } diff --git a/crates/wasi-http/tests/all/async_.rs b/crates/wasi-http/tests/all/async_.rs index 19ce8c1ae5..d79bf445c8 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::preview2::command::Command; +use wasmtime_wasi::command::Command; foreach_http!(assert_test_exists); @@ -13,7 +13,7 @@ async fn run(path: &str, server: &Server) -> Result<()> { let component = Component::from_file(&engine, path)?; let mut store = store(&engine, server); let mut linker = Linker::new(&engine); - wasmtime_wasi::preview2::command::add_to_linker(&mut linker)?; + wasmtime_wasi::command::add_to_linker(&mut linker)?; wasmtime_wasi_http::proxy::add_only_http_to_linker(&mut linker)?; let (command, _instance) = Command::instantiate_async(&mut store, &component, &linker).await?; let result = command.wasi_cli_run().call_run(&mut store).await?; diff --git a/crates/wasi-http/tests/all/main.rs b/crates/wasi-http/tests/all/main.rs index 268c67c508..95e51ac850 100644 --- a/crates/wasi-http/tests/all/main.rs +++ b/crates/wasi-http/tests/all/main.rs @@ -11,7 +11,7 @@ use wasmtime::{ component::{Component, Linker, Resource, ResourceTable}, Config, Engine, Store, }; -use wasmtime_wasi::preview2::{self, pipe::MemoryOutputPipe, WasiCtx, WasiCtxBuilder, WasiView}; +use wasmtime_wasi::{self, pipe::MemoryOutputPipe, WasiCtx, WasiCtxBuilder, WasiView}; use wasmtime_wasi_http::{ bindings::http::types::ErrorCode, body::HyperIncomingBody, @@ -160,7 +160,7 @@ async fn run_wasi_http( let (sender, receiver) = tokio::sync::oneshot::channel(); let out = store.data_mut().new_response_outparam(sender)?; - let handle = preview2::spawn(async move { + let handle = wasmtime_wasi::spawn(async move { proxy .wasi_http_incoming_handler() .call_handle(&mut store, req, out) @@ -267,7 +267,7 @@ async fn do_wasi_http_hash_all(override_send_request: bool) -> Result<()> { let response = handle(request.into_parts().0).map(|resp| { Ok(IncomingResponseInternal { resp, - worker: Arc::new(preview2::spawn(future::ready(()))), + worker: Arc::new(wasmtime_wasi::spawn(future::ready(()))), between_bytes_timeout, }) }); diff --git a/crates/wasi-http/tests/all/sync.rs b/crates/wasi-http/tests/all/sync.rs index 78a4c77cdb..6560927c35 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::preview2::command::sync::Command; +use wasmtime_wasi::command::sync::Command; foreach_http!(assert_test_exists); diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml index 00ecc334d1..5ee1cc2354 100644 --- a/crates/wasi/Cargo.toml +++ b/crates/wasi/Cargo.toml @@ -15,30 +15,26 @@ include = ["src/**/*", "README.md", "LICENSE", "witx/*", "wit/**/*", "tests/*"] workspace = true [dependencies] -wasmtime = { workspace = true } +wasmtime = { workspace = true, features = ["component-model", "async", "runtime"] } anyhow = { workspace = true } wiggle = { workspace = true, optional = true, features = ["wasmtime"] } -once_cell = { workspace = true } -log = { workspace = true } -url = { workspace = true } - -tokio = { workspace = true, optional = true, features = ["time", "sync", "io-std", "io-util", "rt", "rt-multi-thread", "net"] } +tokio = { workspace = true, features = ["time", "sync", "io-std", "io-util", "rt", "rt-multi-thread", "net"] } bytes = { workspace = true } -thiserror = { workspace = true, optional = true } -tracing = { workspace = true, optional = true } -cap-std = { workspace = true, optional = true } -cap-rand = { workspace = true, optional = true } -cap-fs-ext = { workspace = true, optional = true } -cap-net-ext = { workspace = true, optional = true } -cap-time-ext = { workspace = true, optional = true } -io-lifetimes = { workspace = true, optional = true } -fs-set-times = { workspace = true, optional = true } -bitflags = { workspace = true, optional = true } -async-trait = { workspace = true, optional = true } -system-interface = { workspace = true, optional = true} -futures = { workspace = true, optional = true } -wasi-common = { workspace = true, optional = true, features = ["sync"] } -cfg-if = { workspace = true, optional = true } +thiserror = { workspace = true } +tracing = { workspace = true } +cap-std = { workspace = true } +cap-rand = { workspace = true } +cap-fs-ext = { workspace = true } +cap-net-ext = { workspace = true } +cap-time-ext = { workspace = true } +io-lifetimes = { workspace = true } +fs-set-times = { workspace = true } +bitflags = { workspace = true } +async-trait = { workspace = true } +system-interface = { workspace = true} +futures = { workspace = true } +url = { workspace = true } +once_cell = { workspace = true } [dev-dependencies] tokio = { workspace = true, features = ["time", "sync", "io-std", "io-util", "rt", "rt-multi-thread", "net", "macros"] } @@ -49,41 +45,17 @@ tempfile = { workspace = true } wasmtime = { workspace = true, features = ['cranelift'] } [target.'cfg(unix)'.dependencies] -rustix = { workspace = true, features = ["event", "fs", "net"], optional = true } +rustix = { workspace = true, features = ["event", "fs", "net"] } [target.'cfg(windows)'.dependencies] io-extras = { workspace = true } windows-sys = { workspace = true } -rustix = { workspace = true, features = ["event", "net"], optional = true } +rustix = { workspace = true, features = ["event", "net"] } [features] -default = ["wasi-common-deprecations", "preview2", "preview1-on-preview2"] -wasi-common-deprecations = [ "dep:wasi-common" ] -tokio = [ "wasi-common?/tokio", "wasi-common-deprecations" ] -exit = [ "wasi-common-deprecations", "dep:cfg-if" ] -preview2 = [ - 'wasmtime/component-model', - 'wasmtime/async', - 'wasmtime/runtime', - 'dep:thiserror', - 'dep:tracing', - 'dep:cap-std', - 'dep:cap-rand', - 'dep:cap-fs-ext', - 'dep:cap-net-ext', - 'dep:cap-time-ext', - 'dep:io-lifetimes', - 'dep:fs-set-times', - 'dep:bitflags', - 'dep:async-trait', - 'dep:system-interface', - 'dep:rustix', - 'dep:tokio', - 'dep:futures', -] -preview1-on-preview2 = [ - "preview2", - "wiggle", +default = [ "preview1"] +preview1 = [ + "dep:wiggle", ] [[test]] diff --git a/crates/wasi/src/preview2/clocks.rs b/crates/wasi/src/clocks.rs similarity index 100% rename from crates/wasi/src/preview2/clocks.rs rename to crates/wasi/src/clocks.rs diff --git a/crates/wasi/src/preview2/clocks/host.rs b/crates/wasi/src/clocks/host.rs similarity index 100% rename from crates/wasi/src/preview2/clocks/host.rs rename to crates/wasi/src/clocks/host.rs diff --git a/crates/wasi/src/command.rs b/crates/wasi/src/command.rs new file mode 100644 index 0000000000..2638ca1032 --- /dev/null +++ b/crates/wasi/src/command.rs @@ -0,0 +1,122 @@ +use crate::WasiView; + +wasmtime::component::bindgen!({ + world: "wasi:cli/command", + tracing: true, + async: true, + with: { + "wasi:filesystem/types": crate::bindings::filesystem::types, + "wasi:filesystem/preopens": crate::bindings::filesystem::preopens, + "wasi:sockets/tcp": crate::bindings::sockets::tcp, + "wasi:clocks/monotonic_clock": crate::bindings::clocks::monotonic_clock, + "wasi:io/poll": crate::bindings::io::poll, + "wasi:io/streams": crate::bindings::io::streams, + "wasi:clocks/wall_clock": crate::bindings::clocks::wall_clock, + "wasi:random/random": crate::bindings::random::random, + "wasi:cli/environment": crate::bindings::cli::environment, + "wasi:cli/exit": crate::bindings::cli::exit, + "wasi:cli/stdin": crate::bindings::cli::stdin, + "wasi:cli/stdout": crate::bindings::cli::stdout, + "wasi:cli/stderr": crate::bindings::cli::stderr, + "wasi:cli/terminal-input": crate::bindings::cli::terminal_input, + "wasi:cli/terminal-output": crate::bindings::cli::terminal_output, + "wasi:cli/terminal-stdin": crate::bindings::cli::terminal_stdin, + "wasi:cli/terminal-stdout": crate::bindings::cli::terminal_stdout, + "wasi:cli/terminal-stderr": crate::bindings::cli::terminal_stderr, + }, +}); + +pub fn add_to_linker(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> { + crate::bindings::clocks::wall_clock::add_to_linker(l, |t| t)?; + crate::bindings::clocks::monotonic_clock::add_to_linker(l, |t| t)?; + crate::bindings::filesystem::types::add_to_linker(l, |t| t)?; + crate::bindings::filesystem::preopens::add_to_linker(l, |t| t)?; + crate::bindings::io::error::add_to_linker(l, |t| t)?; + crate::bindings::io::poll::add_to_linker(l, |t| t)?; + crate::bindings::io::streams::add_to_linker(l, |t| t)?; + crate::bindings::random::random::add_to_linker(l, |t| t)?; + crate::bindings::random::insecure::add_to_linker(l, |t| t)?; + crate::bindings::random::insecure_seed::add_to_linker(l, |t| t)?; + crate::bindings::cli::exit::add_to_linker(l, |t| t)?; + crate::bindings::cli::environment::add_to_linker(l, |t| t)?; + crate::bindings::cli::stdin::add_to_linker(l, |t| t)?; + crate::bindings::cli::stdout::add_to_linker(l, |t| t)?; + crate::bindings::cli::stderr::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_input::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_output::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_stdin::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_stdout::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_stderr::add_to_linker(l, |t| t)?; + crate::bindings::sockets::tcp::add_to_linker(l, |t| t)?; + crate::bindings::sockets::tcp_create_socket::add_to_linker(l, |t| t)?; + crate::bindings::sockets::udp::add_to_linker(l, |t| t)?; + crate::bindings::sockets::udp_create_socket::add_to_linker(l, |t| t)?; + crate::bindings::sockets::instance_network::add_to_linker(l, |t| t)?; + crate::bindings::sockets::network::add_to_linker(l, |t| t)?; + crate::bindings::sockets::ip_name_lookup::add_to_linker(l, |t| t)?; + Ok(()) +} + +pub mod sync { + use crate::WasiView; + + wasmtime::component::bindgen!({ + world: "wasi:cli/command", + tracing: true, + async: false, + with: { + "wasi:filesystem/types": crate::bindings::sync_io::filesystem::types, + "wasi:filesystem/preopens": crate::bindings::filesystem::preopens, + "wasi:sockets/tcp": crate::bindings::sockets::tcp, + "wasi:sockets/udp": crate::bindings::sockets::udp, + "wasi:clocks/monotonic_clock": crate::bindings::clocks::monotonic_clock, + "wasi:io/poll": crate::bindings::sync_io::io::poll, + "wasi:io/streams": crate::bindings::sync_io::io::streams, + "wasi:clocks/wall_clock": crate::bindings::clocks::wall_clock, + "wasi:random/random": crate::bindings::random::random, + "wasi:cli/environment": crate::bindings::cli::environment, + "wasi:cli/exit": crate::bindings::cli::exit, + "wasi:cli/stdin": crate::bindings::cli::stdin, + "wasi:cli/stdout": crate::bindings::cli::stdout, + "wasi:cli/stderr": crate::bindings::cli::stderr, + "wasi:cli/terminal-input": crate::bindings::cli::terminal_input, + "wasi:cli/terminal-output": crate::bindings::cli::terminal_output, + "wasi:cli/terminal-stdin": crate::bindings::cli::terminal_stdin, + "wasi:cli/terminal-stdout": crate::bindings::cli::terminal_stdout, + "wasi:cli/terminal-stderr": crate::bindings::cli::terminal_stderr, + }, + }); + + pub fn add_to_linker( + l: &mut wasmtime::component::Linker, + ) -> anyhow::Result<()> { + crate::bindings::clocks::wall_clock::add_to_linker(l, |t| t)?; + crate::bindings::clocks::monotonic_clock::add_to_linker(l, |t| t)?; + crate::bindings::sync_io::filesystem::types::add_to_linker(l, |t| t)?; + crate::bindings::filesystem::preopens::add_to_linker(l, |t| t)?; + crate::bindings::io::error::add_to_linker(l, |t| t)?; + crate::bindings::sync_io::io::poll::add_to_linker(l, |t| t)?; + crate::bindings::sync_io::io::streams::add_to_linker(l, |t| t)?; + crate::bindings::random::random::add_to_linker(l, |t| t)?; + crate::bindings::random::insecure::add_to_linker(l, |t| t)?; + crate::bindings::random::insecure_seed::add_to_linker(l, |t| t)?; + crate::bindings::cli::exit::add_to_linker(l, |t| t)?; + crate::bindings::cli::environment::add_to_linker(l, |t| t)?; + crate::bindings::cli::stdin::add_to_linker(l, |t| t)?; + crate::bindings::cli::stdout::add_to_linker(l, |t| t)?; + crate::bindings::cli::stderr::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_input::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_output::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_stdin::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_stdout::add_to_linker(l, |t| t)?; + crate::bindings::cli::terminal_stderr::add_to_linker(l, |t| t)?; + crate::bindings::sockets::tcp::add_to_linker(l, |t| t)?; + crate::bindings::sockets::tcp_create_socket::add_to_linker(l, |t| t)?; + crate::bindings::sockets::udp::add_to_linker(l, |t| t)?; + crate::bindings::sockets::udp_create_socket::add_to_linker(l, |t| t)?; + crate::bindings::sockets::instance_network::add_to_linker(l, |t| t)?; + crate::bindings::sockets::network::add_to_linker(l, |t| t)?; + crate::bindings::sockets::ip_name_lookup::add_to_linker(l, |t| t)?; + Ok(()) + } +} diff --git a/crates/wasi/src/preview2/ctx.rs b/crates/wasi/src/ctx.rs similarity index 99% rename from crates/wasi/src/preview2/ctx.rs rename to crates/wasi/src/ctx.rs index f440fa4e56..090135a0f3 100644 --- a/crates/wasi/src/preview2/ctx.rs +++ b/crates/wasi/src/ctx.rs @@ -1,4 +1,4 @@ -use crate::preview2::{ +use crate::{ clocks::{ host::{monotonic_clock, wall_clock}, HostMonotonicClock, HostWallClock, diff --git a/crates/wasi/src/preview2/error.rs b/crates/wasi/src/error.rs similarity index 100% rename from crates/wasi/src/preview2/error.rs rename to crates/wasi/src/error.rs diff --git a/crates/wasi/src/preview2/filesystem.rs b/crates/wasi/src/filesystem.rs similarity index 98% rename from crates/wasi/src/preview2/filesystem.rs rename to crates/wasi/src/filesystem.rs index de48aa455c..a71305501f 100644 --- a/crates/wasi/src/preview2/filesystem.rs +++ b/crates/wasi/src/filesystem.rs @@ -1,5 +1,5 @@ -use crate::preview2::bindings::filesystem::types; -use crate::preview2::{ +use crate::bindings::filesystem::types; +use crate::{ spawn_blocking, AbortOnDropJoinHandle, HostOutputStream, StreamError, Subscribe, TrappableError, }; use anyhow::anyhow; @@ -85,7 +85,7 @@ pub struct File { /// [`spawn_blocking`]: Self::spawn_blocking pub file: Arc, /// Permissions to enforce on access to the file. These permissions are - /// specified by a user of the `crate::preview2::WasiCtxBuilder`, and are + /// specified by a user of the `crate::WasiCtxBuilder`, and are /// enforced prior to any enforced by the underlying operating system. pub perms: FilePerms, /// The mode the file was opened under: bits for reading, and writing. @@ -134,7 +134,7 @@ pub struct Dir { /// [`spawn_blocking`]: Self::spawn_blocking pub dir: Arc, /// Permissions to enforce on access to this directory. These permissions - /// are specified by a user of the `crate::preview2::WasiCtxBuilder`, and + /// are specified by a user of the `crate::WasiCtxBuilder`, and /// are enforced prior to any enforced by the underlying operating system. /// /// These permissions are also enforced on any directories opened under diff --git a/crates/wasi/src/preview2/host/clocks.rs b/crates/wasi/src/host/clocks.rs similarity index 96% rename from crates/wasi/src/preview2/host/clocks.rs rename to crates/wasi/src/host/clocks.rs index 42b6cb7b92..7faf0acee8 100644 --- a/crates/wasi/src/preview2/host/clocks.rs +++ b/crates/wasi/src/host/clocks.rs @@ -1,11 +1,11 @@ #![allow(unused_variables)] -use crate::preview2::bindings::{ +use crate::bindings::{ clocks::monotonic_clock::{self, Duration as WasiDuration, Instant}, clocks::wall_clock::{self, Datetime}, }; -use crate::preview2::poll::{subscribe, Subscribe}; -use crate::preview2::{Pollable, WasiView}; +use crate::poll::{subscribe, Subscribe}; +use crate::{Pollable, WasiView}; use cap_std::time::SystemTime; use std::time::Duration; use wasmtime::component::Resource; diff --git a/crates/wasi/src/preview2/host/env.rs b/crates/wasi/src/host/env.rs similarity index 83% rename from crates/wasi/src/preview2/host/env.rs rename to crates/wasi/src/host/env.rs index e765dbd817..a107dcdffd 100644 --- a/crates/wasi/src/preview2/host/env.rs +++ b/crates/wasi/src/host/env.rs @@ -1,5 +1,5 @@ -use crate::preview2::bindings::cli::environment; -use crate::preview2::WasiView; +use crate::bindings::cli::environment; +use crate::WasiView; impl environment::Host for T { fn get_environment(&mut self) -> anyhow::Result> { diff --git a/crates/wasi/src/preview2/host/exit.rs b/crates/wasi/src/host/exit.rs similarity index 80% rename from crates/wasi/src/preview2/host/exit.rs rename to crates/wasi/src/host/exit.rs index d95866a9a9..77e12251d0 100644 --- a/crates/wasi/src/preview2/host/exit.rs +++ b/crates/wasi/src/host/exit.rs @@ -1,4 +1,4 @@ -use crate::preview2::{bindings::cli::exit, I32Exit, WasiView}; +use crate::{bindings::cli::exit, I32Exit, WasiView}; impl exit::Host for T { fn exit(&mut self, status: Result<(), ()>) -> anyhow::Result<()> { diff --git a/crates/wasi/src/preview2/host/filesystem.rs b/crates/wasi/src/host/filesystem.rs similarity index 98% rename from crates/wasi/src/preview2/host/filesystem.rs rename to crates/wasi/src/host/filesystem.rs index c6d93713f5..6094bddb72 100644 --- a/crates/wasi/src/preview2/host/filesystem.rs +++ b/crates/wasi/src/host/filesystem.rs @@ -1,13 +1,13 @@ -use crate::preview2::bindings::clocks::wall_clock; -use crate::preview2::bindings::filesystem::preopens; -use crate::preview2::bindings::filesystem::types::{ +use crate::bindings::clocks::wall_clock; +use crate::bindings::filesystem::preopens; +use crate::bindings::filesystem::types::{ self, ErrorCode, HostDescriptor, HostDirectoryEntryStream, }; -use crate::preview2::bindings::io::streams::{InputStream, OutputStream}; -use crate::preview2::filesystem::{ +use crate::bindings::io::streams::{InputStream, OutputStream}; +use crate::filesystem::{ Descriptor, Dir, File, FileInputStream, FileOutputStream, OpenMode, ReaddirIterator, }; -use crate::preview2::{DirPerms, FilePerms, FsError, FsResult, WasiView}; +use crate::{DirPerms, FilePerms, FsError, FsResult, WasiView}; use anyhow::Context; use wasmtime::component::Resource; @@ -982,7 +982,7 @@ impl<'a> From<&'a std::io::Error> for ErrorCode { match from_raw_os_error(err.raw_os_error()) { Some(errno) => errno, None => { - log::debug!("unknown raw os error: {err}"); + tracing::debug!("unknown raw os error: {err}"); match err.kind() { std::io::ErrorKind::NotFound => ErrorCode::NoEntry, std::io::ErrorKind::PermissionDenied => ErrorCode::NotPermitted, diff --git a/crates/wasi/src/preview2/host/filesystem/sync.rs b/crates/wasi/src/host/filesystem/sync.rs similarity index 98% rename from crates/wasi/src/preview2/host/filesystem/sync.rs rename to crates/wasi/src/host/filesystem/sync.rs index 3b3d83e9da..08b446e45a 100644 --- a/crates/wasi/src/preview2/host/filesystem/sync.rs +++ b/crates/wasi/src/host/filesystem/sync.rs @@ -1,7 +1,7 @@ -use crate::preview2::bindings::filesystem::types as async_filesystem; -use crate::preview2::bindings::sync_io::filesystem::types as sync_filesystem; -use crate::preview2::bindings::sync_io::io::streams; -use crate::preview2::{in_tokio, FsError, FsResult}; +use crate::bindings::filesystem::types as async_filesystem; +use crate::bindings::sync_io::filesystem::types as sync_filesystem; +use crate::bindings::sync_io::io::streams; +use crate::{in_tokio, FsError, FsResult}; use wasmtime::component::Resource; impl sync_filesystem::Host for T { diff --git a/crates/wasi/src/preview2/host/instance_network.rs b/crates/wasi/src/host/instance_network.rs similarity index 77% rename from crates/wasi/src/preview2/host/instance_network.rs rename to crates/wasi/src/host/instance_network.rs index 8af4d0d8ae..3471c03828 100644 --- a/crates/wasi/src/preview2/host/instance_network.rs +++ b/crates/wasi/src/host/instance_network.rs @@ -1,6 +1,6 @@ -use crate::preview2::bindings::sockets::instance_network; -use crate::preview2::network::Network; -use crate::preview2::WasiView; +use crate::bindings::sockets::instance_network; +use crate::network::Network; +use crate::WasiView; use wasmtime::component::Resource; impl instance_network::Host for T { diff --git a/crates/wasi/src/preview2/host/io.rs b/crates/wasi/src/host/io.rs similarity index 98% rename from crates/wasi/src/preview2/host/io.rs rename to crates/wasi/src/host/io.rs index b82ccc8efe..656b31bade 100644 --- a/crates/wasi/src/preview2/host/io.rs +++ b/crates/wasi/src/host/io.rs @@ -1,4 +1,4 @@ -use crate::preview2::{ +use crate::{ bindings::io::error, bindings::io::streams::{self, InputStream, OutputStream}, poll::subscribe, @@ -161,7 +161,7 @@ impl streams::HostOutputStream for T { src: Resource, len: u64, ) -> StreamResult { - use crate::preview2::Subscribe; + use crate::Subscribe; self.table().get_mut(&dest)?.ready().await; @@ -220,12 +220,12 @@ impl streams::HostInputStream for T { } fn subscribe(&mut self, stream: Resource) -> anyhow::Result> { - crate::preview2::poll::subscribe(self.table(), stream) + crate::poll::subscribe(self.table(), stream) } } pub mod sync { - use crate::preview2::{ + use crate::{ bindings::io::streams::{ self as async_streams, Host as AsyncHost, HostInputStream as AsyncHostInputStream, HostOutputStream as AsyncHostOutputStream, diff --git a/crates/wasi/src/preview2/host/mod.rs b/crates/wasi/src/host/mod.rs similarity index 100% rename from crates/wasi/src/preview2/host/mod.rs rename to crates/wasi/src/host/mod.rs diff --git a/crates/wasi/src/preview2/host/network.rs b/crates/wasi/src/host/network.rs similarity index 97% rename from crates/wasi/src/preview2/host/network.rs rename to crates/wasi/src/host/network.rs index 995652a1a4..be832d448a 100644 --- a/crates/wasi/src/preview2/host/network.rs +++ b/crates/wasi/src/host/network.rs @@ -1,9 +1,9 @@ -use crate::preview2::bindings::sockets::network::{ +use crate::bindings::sockets::network::{ self, ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress, Ipv6SocketAddress, }; -use crate::preview2::network::{from_ipv4_addr, from_ipv6_addr, to_ipv4_addr, to_ipv6_addr}; -use crate::preview2::{SocketError, WasiView}; +use crate::network::{from_ipv4_addr, from_ipv6_addr, to_ipv4_addr, to_ipv6_addr}; +use crate::{SocketError, WasiView}; use rustix::io::Errno; use std::io; use wasmtime::component::Resource; @@ -14,7 +14,7 @@ impl network::Host for T { } } -impl crate::preview2::bindings::sockets::network::HostNetwork for T { +impl crate::bindings::sockets::network::HostNetwork for T { fn drop(&mut self, this: Resource) -> Result<(), anyhow::Error> { let table = self.table(); @@ -47,7 +47,7 @@ impl From for ErrorCode { std::io::ErrorKind::WouldBlock => ErrorCode::WouldBlock, _ => { - log::debug!("unknown I/O error: {value}"); + tracing::debug!("unknown I/O error: {value}"); ErrorCode::Unknown } } @@ -98,7 +98,7 @@ impl From for ErrorCode { // FYI, EINPROGRESS should have already been handled by connect. _ => { - log::debug!("unknown I/O error: {value}"); + tracing::debug!("unknown I/O error: {value}"); ErrorCode::Unknown } } @@ -215,9 +215,9 @@ pub(crate) mod util { use std::net::{IpAddr, Ipv6Addr, SocketAddr}; use std::time::Duration; - use crate::preview2::bindings::sockets::network::ErrorCode; - use crate::preview2::network::SocketAddressFamily; - use crate::preview2::SocketResult; + use crate::bindings::sockets::network::ErrorCode; + use crate::network::SocketAddressFamily; + use crate::SocketResult; use cap_net_ext::{AddressFamily, Blocking, UdpSocketExt}; use rustix::fd::{AsFd, OwnedFd}; use rustix::io::Errno; diff --git a/crates/wasi/src/preview2/host/random.rs b/crates/wasi/src/host/random.rs similarity index 90% rename from crates/wasi/src/preview2/host/random.rs rename to crates/wasi/src/host/random.rs index 583ff8e98e..e837bf1302 100644 --- a/crates/wasi/src/preview2/host/random.rs +++ b/crates/wasi/src/host/random.rs @@ -1,5 +1,5 @@ -use crate::preview2::bindings::random::{insecure, insecure_seed, random}; -use crate::preview2::WasiView; +use crate::bindings::random::{insecure, insecure_seed, random}; +use crate::WasiView; use cap_rand::{distributions::Standard, Rng}; impl random::Host for T { diff --git a/crates/wasi/src/preview2/host/tcp.rs b/crates/wasi/src/host/tcp.rs similarity index 98% rename from crates/wasi/src/preview2/host/tcp.rs rename to crates/wasi/src/host/tcp.rs index 5780ed864f..0f08862f79 100644 --- a/crates/wasi/src/preview2/host/tcp.rs +++ b/crates/wasi/src/host/tcp.rs @@ -1,7 +1,7 @@ -use crate::preview2::host::network::util; -use crate::preview2::network::SocketAddrUse; -use crate::preview2::tcp::{TcpReadStream, TcpSocket, TcpState, TcpWriteStream}; -use crate::preview2::{ +use crate::host::network::util; +use crate::network::SocketAddrUse; +use crate::tcp::{TcpReadStream, TcpSocket, TcpState, TcpWriteStream}; +use crate::{ bindings::{ io::streams::{InputStream, OutputStream}, sockets::network::{ErrorCode, IpAddressFamily, IpSocketAddress, Network}, @@ -9,7 +9,7 @@ use crate::preview2::{ }, network::SocketAddressFamily, }; -use crate::preview2::{with_ambient_tokio_runtime, Pollable, SocketResult, WasiView}; +use crate::{with_ambient_tokio_runtime, Pollable, SocketResult, WasiView}; use io_lifetimes::AsSocketlike; use rustix::io::Errno; use rustix::net::sockopt; @@ -21,7 +21,7 @@ use wasmtime::component::Resource; impl tcp::Host for T {} -impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { +impl crate::host::tcp::tcp::HostTcpSocket for T { fn start_bind( &mut self, this: Resource, @@ -636,7 +636,7 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { } fn subscribe(&mut self, this: Resource) -> anyhow::Result> { - crate::preview2::poll::subscribe(self.table(), this) + crate::poll::subscribe(self.table(), this) } fn shutdown( diff --git a/crates/wasi/src/preview2/host/tcp_create_socket.rs b/crates/wasi/src/host/tcp_create_socket.rs similarity index 66% rename from crates/wasi/src/preview2/host/tcp_create_socket.rs rename to crates/wasi/src/host/tcp_create_socket.rs index 90991cb4b8..dc9212406e 100644 --- a/crates/wasi/src/preview2/host/tcp_create_socket.rs +++ b/crates/wasi/src/host/tcp_create_socket.rs @@ -1,6 +1,6 @@ -use crate::preview2::bindings::{sockets::network::IpAddressFamily, sockets::tcp_create_socket}; -use crate::preview2::tcp::TcpSocket; -use crate::preview2::{SocketResult, WasiView}; +use crate::bindings::{sockets::network::IpAddressFamily, sockets::tcp_create_socket}; +use crate::tcp::TcpSocket; +use crate::{SocketResult, WasiView}; use wasmtime::component::Resource; impl tcp_create_socket::Host for T { diff --git a/crates/wasi/src/preview2/host/udp.rs b/crates/wasi/src/host/udp.rs similarity index 97% rename from crates/wasi/src/preview2/host/udp.rs rename to crates/wasi/src/host/udp.rs index a333400171..7ab1787872 100644 --- a/crates/wasi/src/preview2/host/udp.rs +++ b/crates/wasi/src/host/udp.rs @@ -1,6 +1,6 @@ -use crate::preview2::host::network::util; -use crate::preview2::network::{SocketAddrUse, SocketAddressFamily}; -use crate::preview2::{ +use crate::host::network::util; +use crate::network::{SocketAddrUse, SocketAddressFamily}; +use crate::{ bindings::{ sockets::network::{ErrorCode, IpAddressFamily, IpSocketAddress, Network}, sockets::udp, @@ -8,7 +8,7 @@ use crate::preview2::{ udp::{IncomingDatagramStream, OutgoingDatagramStream, SendState, UdpState}, Subscribe, }; -use crate::preview2::{Pollable, SocketError, SocketResult, WasiView}; +use crate::{Pollable, SocketError, SocketResult, WasiView}; use anyhow::anyhow; use async_trait::async_trait; use io_lifetimes::AsSocketlike; @@ -139,7 +139,9 @@ impl udp::HostUdpSocket for T { |error| match error { Errno::AFNOSUPPORT => ErrorCode::InvalidArgument, // See `bind` implementation. Errno::INPROGRESS => { - log::debug!("UDP connect returned EINPROGRESS, which should never happen"); + tracing::debug!( + "UDP connect returned EINPROGRESS, which should never happen" + ); ErrorCode::Unknown } _ => ErrorCode::from(error), @@ -283,7 +285,7 @@ impl udp::HostUdpSocket for T { } fn subscribe(&mut self, this: Resource) -> anyhow::Result> { - crate::preview2::poll::subscribe(self.table(), this) + crate::poll::subscribe(self.table(), this) } fn drop(&mut self, this: Resource) -> Result<(), anyhow::Error> { @@ -363,7 +365,7 @@ impl udp::HostIncomingDatagramStream for T { &mut self, this: Resource, ) -> anyhow::Result> { - crate::preview2::poll::subscribe(self.table(), this) + crate::poll::subscribe(self.table(), this) } fn drop(&mut self, this: Resource) -> Result<(), anyhow::Error> { @@ -497,7 +499,7 @@ impl udp::HostOutgoingDatagramStream for T { &mut self, this: Resource, ) -> anyhow::Result> { - crate::preview2::poll::subscribe(self.table(), this) + crate::poll::subscribe(self.table(), this) } fn drop(&mut self, this: Resource) -> Result<(), anyhow::Error> { diff --git a/crates/wasi/src/preview2/host/udp_create_socket.rs b/crates/wasi/src/host/udp_create_socket.rs similarity index 66% rename from crates/wasi/src/preview2/host/udp_create_socket.rs rename to crates/wasi/src/host/udp_create_socket.rs index f087eb3303..1a0c4b9eb0 100644 --- a/crates/wasi/src/preview2/host/udp_create_socket.rs +++ b/crates/wasi/src/host/udp_create_socket.rs @@ -1,6 +1,6 @@ -use crate::preview2::bindings::{sockets::network::IpAddressFamily, sockets::udp_create_socket}; -use crate::preview2::udp::UdpSocket; -use crate::preview2::{SocketResult, WasiView}; +use crate::bindings::{sockets::network::IpAddressFamily, sockets::udp_create_socket}; +use crate::udp::UdpSocket; +use crate::{SocketResult, WasiView}; use wasmtime::component::Resource; impl udp_create_socket::Host for T { diff --git a/crates/wasi/src/preview2/ip_name_lookup.rs b/crates/wasi/src/ip_name_lookup.rs similarity index 83% rename from crates/wasi/src/preview2/ip_name_lookup.rs rename to crates/wasi/src/ip_name_lookup.rs index dd92433999..85f5e8e6e2 100644 --- a/crates/wasi/src/preview2/ip_name_lookup.rs +++ b/crates/wasi/src/ip_name_lookup.rs @@ -1,8 +1,8 @@ -use crate::preview2::bindings::sockets::ip_name_lookup::{Host, HostResolveAddressStream}; -use crate::preview2::bindings::sockets::network::{ErrorCode, IpAddress, Network}; -use crate::preview2::host::network::util; -use crate::preview2::poll::{subscribe, Pollable, Subscribe}; -use crate::preview2::{spawn_blocking, AbortOnDropJoinHandle, SocketError, WasiView}; +use crate::bindings::sockets::ip_name_lookup::{Host, HostResolveAddressStream}; +use crate::bindings::sockets::network::{ErrorCode, IpAddress, Network}; +use crate::host::network::util; +use crate::poll::{subscribe, Pollable, Subscribe}; +use crate::{spawn_blocking, AbortOnDropJoinHandle, SocketError, WasiView}; use anyhow::Result; use std::mem; use std::net::{Ipv6Addr, ToSocketAddrs}; @@ -48,14 +48,12 @@ impl HostResolveAddressStream for T { let stream: &mut ResolveAddressStream = self.table().get_mut(&resource)?; loop { match stream { - ResolveAddressStream::Waiting(future) => { - match crate::preview2::poll_noop(Pin::new(future)) { - Some(result) => { - *stream = ResolveAddressStream::Done(result.map(|v| v.into_iter())); - } - None => return Err(ErrorCode::WouldBlock.into()), + ResolveAddressStream::Waiting(future) => match crate::poll_noop(Pin::new(future)) { + Some(result) => { + *stream = ResolveAddressStream::Done(result.map(|v| v.into_iter())); } - } + None => return Err(ErrorCode::WouldBlock.into()), + }, ResolveAddressStream::Done(slot @ Err(_)) => { mem::replace(slot, Ok(Vec::new().into_iter()))?; unreachable!(); diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs index 3dcb8d271d..8262d889be 100644 --- a/crates/wasi/src/lib.rs +++ b/crates/wasi/src/lib.rs @@ -1,103 +1,318 @@ -//! `wasmtime-wasi` now supports using multiple snapshots to interface to the -//! same `WasiCtx`! +//! # Wasmtime's WASI Implementation +//! +//! This crate provides a Wasmtime host implementation of WASI 0.2 (aka +//! Preview 2), and a compatibility shim that provides an implementation of +//! WASI 0.1 (aka Preview 1). //! -//! `wasmtime_wasi::Wasi::new(&Store, WasiCtx)` is a struct which owns your -//! `WasiCtx` and provides linkage to every available snapshot. //! -//! Individual snapshots are available through -//! `wasmtime_wasi::snapshots::preview_{0, 1}::Wasi::new(&Store, Rc>)`. -#![warn(clippy::cast_sign_loss)] +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; -#[cfg(feature = "preview2")] -pub mod preview2; +mod clocks; +pub mod command; +mod ctx; +mod error; +mod filesystem; +mod host; +mod ip_name_lookup; +mod network; +pub mod pipe; +mod poll; +#[cfg(feature = "preview1")] +pub mod preview0; +#[cfg(feature = "preview1")] +pub mod preview1; +mod random; +mod stdio; +mod stream; +mod tcp; +mod udp; +mod write_stream; -#[cfg(feature = "wasi-common-deprecations")] -#[deprecated( - since = "18.0.0", - note = "The wasmtime_wasi::sync module's functionalty has been moved to - wasi_common::sync. This re-export will be removed from wasmtime_wasi in - 19.0" -)] -pub mod sync { - pub use wasi_common::sync::*; -} +pub use self::clocks::{HostMonotonicClock, HostWallClock}; +pub use self::ctx::{WasiCtx, WasiCtxBuilder, WasiView}; +pub use self::error::{I32Exit, TrappableError}; +pub use self::filesystem::{DirPerms, FilePerms, FsError, FsResult}; +pub use self::network::{Network, SocketError, SocketResult}; +pub use self::poll::{subscribe, ClosureFuture, MakeFuture, Pollable, PollableFuture, Subscribe}; +pub use self::random::{thread_rng, Deterministic}; +pub use self::stdio::{ + stderr, stdin, stdout, IsATTY, Stderr, Stdin, StdinStream, Stdout, StdoutStream, +}; +pub use self::stream::{ + HostInputStream, HostOutputStream, InputStream, OutputStream, StreamError, StreamResult, +}; +pub use cap_fs_ext::SystemTimeSpec; +pub use cap_rand::RngCore; +pub use wasmtime::component::{ResourceTable, ResourceTableError}; + +pub mod bindings { + // Generate traits for synchronous bindings. + // + // Note that this is only done for interfaces which can block, or those which + // have some functions in `only_imports` below for being async. + pub mod sync_io { + pub(crate) mod _internal { + use crate::{FsError, StreamError}; + + wasmtime::component::bindgen!({ + path: "wit", + interfaces: " + import wasi:io/poll@0.2.0; + import wasi:io/streams@0.2.0; + import wasi:filesystem/types@0.2.0; + ", + tracing: true, + trappable_error_type: { + "wasi:io/streams/stream-error" => StreamError, + "wasi:filesystem/types/error-code" => FsError, + }, + with: { + "wasi:clocks/wall-clock": crate::bindings::clocks::wall_clock, + "wasi:filesystem/types/descriptor": super::super::filesystem::types::Descriptor, + "wasi:filesystem/types/directory-entry-stream": super::super::filesystem::types::DirectoryEntryStream, + "wasi:io/poll/pollable": super::super::io::poll::Pollable, + "wasi:io/streams/input-stream": super::super::io::streams::InputStream, + "wasi:io/streams/output-stream": super::super::io::streams::OutputStream, + "wasi:io/error/error": super::super::io::error::Error, + } + }); + } + pub use self::_internal::wasi::{filesystem, io}; + } -#[cfg(feature = "wasi-common-deprecations")] -#[allow(deprecated)] // Satisfy linter locally -#[deprecated( - since = "18.0.0", - note = "The wasmtime_wasi module's root export of wasmtime_wasi::sync has - been moved to wasi_common::sync. This re-export will be removed from - wasmtime_wasi in 19.0" -)] -pub use sync::*; + wasmtime::component::bindgen!({ + path: "wit", + world: "wasi:cli/imports", + tracing: 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: [ + "[method]descriptor.access-at", + "[method]descriptor.advise", + "[method]descriptor.change-directory-permissions-at", + "[method]descriptor.change-file-permissions-at", + "[method]descriptor.create-directory-at", + "[method]descriptor.get-flags", + "[method]descriptor.get-type", + "[method]descriptor.is-same-object", + "[method]descriptor.link-at", + "[method]descriptor.lock-exclusive", + "[method]descriptor.lock-shared", + "[method]descriptor.metadata-hash", + "[method]descriptor.metadata-hash-at", + "[method]descriptor.open-at", + "[method]descriptor.read", + "[method]descriptor.read-directory", + "[method]descriptor.readlink-at", + "[method]descriptor.remove-directory-at", + "[method]descriptor.rename-at", + "[method]descriptor.set-size", + "[method]descriptor.set-times", + "[method]descriptor.set-times-at", + "[method]descriptor.stat", + "[method]descriptor.stat-at", + "[method]descriptor.symlink-at", + "[method]descriptor.sync", + "[method]descriptor.sync-data", + "[method]descriptor.try-lock-exclusive", + "[method]descriptor.try-lock-shared", + "[method]descriptor.unlink-file-at", + "[method]descriptor.unlock", + "[method]descriptor.write", + "[method]input-stream.read", + "[method]input-stream.blocking-read", + "[method]input-stream.blocking-skip", + "[method]input-stream.skip", + "[method]output-stream.forward", + "[method]output-stream.splice", + "[method]output-stream.blocking-splice", + "[method]output-stream.blocking-flush", + "[method]output-stream.blocking-write", + "[method]output-stream.blocking-write-and-flush", + "[method]output-stream.blocking-write-zeroes-and-flush", + "[method]directory-entry-stream.read-directory-entry", + "poll", + "[method]pollable.block", + "[method]pollable.ready", + ], + }, + trappable_error_type: { + "wasi:io/streams/stream-error" => crate::StreamError, + "wasi:filesystem/types/error-code" => crate::FsError, + "wasi:sockets/network/error-code" => crate::SocketError, + }, + with: { + "wasi:sockets/network/network": super::network::Network, + "wasi:sockets/tcp/tcp-socket": super::tcp::TcpSocket, + "wasi:sockets/udp/udp-socket": super::udp::UdpSocket, + "wasi:sockets/udp/incoming-datagram-stream": super::udp::IncomingDatagramStream, + "wasi:sockets/udp/outgoing-datagram-stream": super::udp::OutgoingDatagramStream, + "wasi:sockets/ip-name-lookup/resolve-address-stream": super::ip_name_lookup::ResolveAddressStream, + "wasi:filesystem/types/directory-entry-stream": super::filesystem::ReaddirIterator, + "wasi:filesystem/types/descriptor": super::filesystem::Descriptor, + "wasi:io/streams/input-stream": super::stream::InputStream, + "wasi:io/streams/output-stream": super::stream::OutputStream, + "wasi:io/error/error": super::stream::Error, + "wasi:io/poll/pollable": super::poll::Pollable, + "wasi:cli/terminal-input/terminal-input": super::stdio::TerminalInput, + "wasi:cli/terminal-output/terminal-output": super::stdio::TerminalOutput, + }, + }); -#[cfg(feature = "tokio")] -#[deprecated( - since = "18.0.0", - note = "The wasmtime_wasi::tokio module's functionalty has been moved to - wasi_common::tokio. This re-export will be removed from wasmtime_wasi in - 19.0" -)] -pub mod tokio { - pub use wasi_common::tokio::*; + pub use wasi::*; } -/// Exit the process with a conventional OS error code as long as Wasmtime -/// understands the error. If the error is not an `I32Exit` or `Trap`, return -/// the error back to the caller for it to decide what to do. -/// -/// Note: this function is designed for usage where it is acceptable for -/// Wasmtime failures to terminate the parent process, such as in the Wasmtime -/// CLI; this would not be suitable for use in multi-tenant embeddings. -#[cfg(feature = "exit")] -#[deprecated( - since = "18.0.0", - note = "This legacy functionality is migrated to the wasi-common crate, and will be removed in 19.0." -)] -pub fn maybe_exit_on_error(e: anyhow::Error) -> anyhow::Error { - use std::process; - use wasmtime::Trap; +pub(crate) static RUNTIME: once_cell::sync::Lazy = + once_cell::sync::Lazy::new(|| { + tokio::runtime::Builder::new_current_thread() + .enable_time() + .enable_io() + .build() + .unwrap() + }); - if let Some(exit) = e - .downcast_ref::() - .map(|exit| exit.process_exit_code()) - { - process::exit(exit) +pub struct AbortOnDropJoinHandle(tokio::task::JoinHandle); +impl Drop for AbortOnDropJoinHandle { + fn drop(&mut self) { + self.0.abort() } - - // If a specific WASI error code was requested then that's - // forwarded through to the process here without printing any - // extra error information. - let code = e.downcast_ref::().map(|e| e.0); - if let Some(exit) = code { - // Print the error message in the usual way. - // On Windows, exit status 3 indicates an abort (see below), - // so return 1 indicating a non-zero status to avoid ambiguity. - if cfg!(windows) && exit >= 3 { - process::exit(1); +} +impl std::ops::Deref for AbortOnDropJoinHandle { + type Target = tokio::task::JoinHandle; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl std::ops::DerefMut for AbortOnDropJoinHandle { + fn deref_mut(&mut self) -> &mut tokio::task::JoinHandle { + &mut self.0 + } +} +impl From> for AbortOnDropJoinHandle { + fn from(jh: tokio::task::JoinHandle) -> Self { + AbortOnDropJoinHandle(jh) + } +} +impl Future for AbortOnDropJoinHandle { + type Output = T; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match Pin::new(&mut self.as_mut().0).poll(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(r) => Poll::Ready(r.expect("child task panicked")), } - process::exit(exit); } +} + +pub fn spawn(f: F) -> AbortOnDropJoinHandle +where + F: Future + Send + 'static, + F::Output: Send + 'static, +{ + let j = with_ambient_tokio_runtime(|| tokio::task::spawn(f)); + AbortOnDropJoinHandle(j) +} - // If the program exited because of a trap, return an error code - // to the outside environment indicating a more severe problem - // than a simple failure. - if e.is::() { - eprintln!("Error: {:?}", e); +pub fn spawn_blocking(f: F) -> AbortOnDropJoinHandle +where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, +{ + let j = with_ambient_tokio_runtime(|| tokio::task::spawn_blocking(f)); + AbortOnDropJoinHandle(j) +} + +pub fn in_tokio(f: F) -> F::Output { + match tokio::runtime::Handle::try_current() { + Ok(h) => { + let _enter = h.enter(); + h.block_on(f) + } + // The `yield_now` here is non-obvious and if you're reading this + // you're likely curious about why it's here. This is currently required + // to get some features of "sync mode" working correctly, such as with + // the CLI. To illustrate why this is required, consider a program + // organized as: + // + // * A program has a `pollable` that it's waiting on. + // * This `pollable` is always ready . + // * Actually making the corresponding operation ready, however, + // requires some background work on Tokio's part. + // * The program is looping on "wait for readiness" coupled with + // performing the operation. + // + // In this situation this program ends up infinitely looping in waiting + // for pollables. The reason appears to be that when we enter the tokio + // runtime here it doesn't necessary yield to background work because + // the provided future `f` is ready immediately. The future `f` will run + // through the list of pollables and determine one of them is ready. + // + // Historically this happened with UDP sockets. A test send a datagram + // from one socket to another and the other socket infinitely didn't + // receive the data. This appeared to be because the server socket was + // waiting on `READABLE | WRITABLE` (which is itself a bug but ignore + // that) and the socket was currently in the "writable" state but never + // ended up receiving a notification for the "readable" state. Moving + // the socket to "readable" would require Tokio to perform some + // background work via epoll/kqueue/handle events but if the future + // provided here is always ready, then that never happened. + // + // Thus the `yield_now()` is an attempt to force Tokio to go do some + // background work eventually and look at new interest masks for + // example. This is a bit of a kludge but everything's already a bit + // wonky in synchronous mode anyway. Note that this is hypothesized to + // not be an issue in async mode because async mode typically has the + // Tokio runtime in a separate thread or otherwise participating in a + // larger application, it's only here in synchronous mode where we + // effectively own the runtime that we need some special care. + Err(_) => { + let _enter = RUNTIME.enter(); + RUNTIME.block_on(async move { + tokio::task::yield_now().await; + f.await + }) + } + } +} - cfg_if::cfg_if! { - if #[cfg(unix)] { - // On Unix, return the error code of an abort. - process::exit(rustix::process::EXIT_SIGNALED_SIGABRT); - } else if #[cfg(windows)] { - // On Windows, return 3. - // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/abort?view=vs-2019 - process::exit(3); - } +/// Executes the closure `f` with an "ambient Tokio runtime" which basically +/// means that if code in `f` tries to get a runtime `Handle` it'll succeed. +/// +/// If a `Handle` is already available, e.g. in async contexts, then `f` is run +/// immediately. Otherwise for synchronous contexts this crate's fallback +/// runtime is configured and then `f` is executed. +pub fn with_ambient_tokio_runtime(f: impl FnOnce() -> R) -> R { + match tokio::runtime::Handle::try_current() { + Ok(_) => f(), + Err(_) => { + let _enter = RUNTIME.enter(); + f() } } +} - e +/// Attempts to get the result of a `future`. +/// +/// This function does not block and will poll the provided future once. If the +/// result is here then `Some` is returned, otherwise `None` is returned. +/// +/// Note that by polling `future` this means that `future` must be re-polled +/// later if it's to wake up a task. +pub fn poll_noop(future: Pin<&mut F>) -> Option +where + F: Future, +{ + let mut task = Context::from_waker(futures::task::noop_waker_ref()); + match future.poll(&mut task) { + Poll::Ready(result) => Some(result), + Poll::Pending => None, + } } diff --git a/crates/wasi/src/preview2/network.rs b/crates/wasi/src/network.rs similarity index 93% rename from crates/wasi/src/preview2/network.rs rename to crates/wasi/src/network.rs index 82b0929bcd..43870182f8 100644 --- a/crates/wasi/src/preview2/network.rs +++ b/crates/wasi/src/network.rs @@ -1,6 +1,6 @@ -use crate::preview2::bindings::sockets::network::{Ipv4Address, Ipv6Address}; -use crate::preview2::bindings::wasi::sockets::network::ErrorCode; -use crate::preview2::TrappableError; +use crate::bindings::sockets::network::{Ipv4Address, Ipv6Address}; +use crate::bindings::wasi::sockets::network::ErrorCode; +use crate::TrappableError; use std::net::SocketAddr; use std::sync::Arc; diff --git a/crates/wasi/src/preview2/pipe.rs b/crates/wasi/src/pipe.rs similarity index 99% rename from crates/wasi/src/preview2/pipe.rs rename to crates/wasi/src/pipe.rs index 413de2e7f6..48706a2c82 100644 --- a/crates/wasi/src/preview2/pipe.rs +++ b/crates/wasi/src/pipe.rs @@ -7,14 +7,14 @@ //! Some convenience constructors are included for common backing types like `Vec` and `String`, //! but the virtual pipes can be instantiated with any `Read` or `Write` type. //! -use crate::preview2::poll::Subscribe; -use crate::preview2::{HostInputStream, HostOutputStream, StreamError}; +use crate::poll::Subscribe; +use crate::{HostInputStream, HostOutputStream, StreamError}; use anyhow::anyhow; use bytes::Bytes; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc; -pub use crate::preview2::write_stream::AsyncWriteStream; +pub use crate::write_stream::AsyncWriteStream; #[derive(Debug, Clone)] pub struct MemoryInputPipe { @@ -112,7 +112,7 @@ pub struct AsyncReadStream { closed: bool, buffer: Option>, receiver: mpsc::Receiver>, - _join_handle: crate::preview2::AbortOnDropJoinHandle<()>, + _join_handle: crate::AbortOnDropJoinHandle<()>, } impl AsyncReadStream { @@ -120,7 +120,7 @@ impl AsyncReadStream { /// provided by this struct, the argument must impl [`tokio::io::AsyncRead`]. pub fn new(mut reader: T) -> Self { let (sender, receiver) = mpsc::channel(1); - let join_handle = crate::preview2::spawn(async move { + let join_handle = crate::spawn(async move { loop { use tokio::io::AsyncReadExt; let mut buf = bytes::BytesMut::with_capacity(4096); diff --git a/crates/wasi/src/preview2/poll.rs b/crates/wasi/src/poll.rs similarity index 96% rename from crates/wasi/src/preview2/poll.rs rename to crates/wasi/src/poll.rs index 139d9c1804..1edeae693b 100644 --- a/crates/wasi/src/preview2/poll.rs +++ b/crates/wasi/src/poll.rs @@ -1,4 +1,4 @@ -use crate::preview2::{bindings::io::poll, WasiView}; +use crate::{bindings::io::poll, WasiView}; use anyhow::{anyhow, Result}; use std::any::Any; use std::collections::HashMap; @@ -123,7 +123,7 @@ impl poll::Host for T { } #[async_trait::async_trait] -impl crate::preview2::bindings::io::poll::HostPollable for T { +impl crate::bindings::io::poll::HostPollable for T { async fn block(&mut self, pollable: Resource) -> Result<()> { let table = self.table(); let pollable = table.get(&pollable)?; @@ -151,7 +151,7 @@ impl crate::preview2::bindings::io::poll::HostPollable for T { } pub mod sync { - use crate::preview2::{ + use crate::{ bindings::io::poll as async_poll, bindings::sync_io::io::poll::{self, Pollable}, in_tokio, WasiView, @@ -165,7 +165,7 @@ pub mod sync { } } - impl crate::preview2::bindings::sync_io::io::poll::HostPollable for T { + impl crate::bindings::sync_io::io::poll::HostPollable for T { fn ready(&mut self, pollable: Resource) -> Result { in_tokio(async { async_poll::HostPollable::ready(self, pollable).await }) } diff --git a/crates/wasi/src/preview2/preview0.rs b/crates/wasi/src/preview0.rs similarity index 98% rename from crates/wasi/src/preview2/preview0.rs rename to crates/wasi/src/preview0.rs index 71c390cdfc..64c28aeb7a 100644 --- a/crates/wasi/src/preview2/preview0.rs +++ b/crates/wasi/src/preview0.rs @@ -1,7 +1,7 @@ -use crate::preview2::preview0::types::Error; -use crate::preview2::preview1::types as snapshot1_types; -use crate::preview2::preview1::wasi_snapshot_preview1::WasiSnapshotPreview1 as Snapshot1; -use crate::preview2::preview1::WasiPreview1View; +use crate::preview0::types::Error; +use crate::preview1::types as snapshot1_types; +use crate::preview1::wasi_snapshot_preview1::WasiSnapshotPreview1 as Snapshot1; +use crate::preview1::WasiPreview1View; use wiggle::{GuestError, GuestPtr}; pub fn add_to_linker_async( @@ -52,7 +52,7 @@ mod sync { // Small wrapper around `in_tokio` to add a `Result` layer which is always // `Ok` fn in_tokio(future: F) -> Result { - Ok(crate::preview2::in_tokio(future)) + Ok(crate::in_tokio(future)) } } diff --git a/crates/wasi/src/preview2/preview1.rs b/crates/wasi/src/preview1.rs similarity index 99% rename from crates/wasi/src/preview2/preview1.rs rename to crates/wasi/src/preview1.rs index 2b1ddc95eb..2d0f0fb7ba 100644 --- a/crates/wasi/src/preview2/preview1.rs +++ b/crates/wasi/src/preview1.rs @@ -1,4 +1,4 @@ -use crate::preview2::bindings::{ +use crate::bindings::{ self, cli::{ stderr, stdin, stdout, terminal_input, terminal_output, terminal_stderr, terminal_stdin, @@ -8,7 +8,7 @@ use crate::preview2::bindings::{ filesystem::{preopens, types as filesystem}, io::{poll, streams}, }; -use crate::preview2::{FsError, IsATTY, StreamError, StreamResult, WasiView}; +use crate::{FsError, IsATTY, StreamError, StreamResult, WasiView}; use anyhow::{bail, Context}; use std::borrow::Borrow; use std::collections::{BTreeMap, HashSet}; @@ -23,7 +23,7 @@ use wiggle::{GuestError, GuestPtr, GuestStrCow, GuestType}; #[derive(Debug)] struct File { - /// The handle to the preview2 descriptor of type [`crate::preview2::filesystem::Descriptor::File`]. + /// The handle to the preview2 descriptor of type [`crate::filesystem::Descriptor::File`]. fd: Resource, /// The current-position pointer. @@ -151,14 +151,14 @@ enum Descriptor { stream: Resource, isatty: IsATTY, }, - /// A fd of type [`crate::preview2::filesystem::Descriptor::Dir`] + /// A fd of type [`crate::filesystem::Descriptor::Dir`] Directory { fd: Resource, /// The path this directory was preopened as. /// `None` means this directory was opened using `open-at`. preopen_path: Option, }, - /// A fd of type [`crate::preview2::filesystem::Descriptor::File`] + /// A fd of type [`crate::filesystem::Descriptor::File`] File(File), } @@ -464,7 +464,7 @@ trait WasiPreview1ViewExt: /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`] /// and returns [`filesystem::Descriptor`] corresponding to `fd` - /// if it describes a [`Descriptor::File`] of [`crate::preview2::filesystem::File`] type + /// if it describes a [`Descriptor::File`] of [`crate::filesystem::File`] type fn get_file_fd( &mut self, fd: types::Fd, @@ -477,7 +477,7 @@ trait WasiPreview1ViewExt: /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`] /// and returns [`filesystem::Descriptor`] corresponding to `fd` /// if it describes a [`Descriptor::File`] or [`Descriptor::PreopenDirectory`] - /// of [`crate::preview2::filesystem::Dir`] type + /// of [`crate::filesystem::Dir`] type fn get_dir_fd( &mut self, fd: types::Fd, @@ -542,7 +542,7 @@ mod sync { // Small wrapper around `in_tokio` to add a `Result` layer which is always // `Ok` fn in_tokio(future: F) -> Result { - Ok(crate::preview2::in_tokio(future)) + Ok(crate::in_tokio(future)) } } @@ -559,7 +559,7 @@ impl From for types::Error { StreamError::LastOperationFailed(e) => match e.downcast::() { Ok(err) => filesystem::ErrorCode::from(err).into(), Err(e) => { - log::debug!("dropping error {e:?}"); + tracing::debug!("dropping error {e:?}"); types::Errno::Io.into() } }, @@ -1918,11 +1918,11 @@ impl< })?; let mut t = self.transact()?; let desc = match t.view.table().get(&fd)? { - crate::preview2::filesystem::Descriptor::Dir(_) => Descriptor::Directory { + crate::filesystem::Descriptor::Dir(_) => Descriptor::Directory { fd, preopen_path: None, }, - crate::preview2::filesystem::Descriptor::File(_) => Descriptor::File(File { + crate::filesystem::Descriptor::File(_) => Descriptor::File(File { fd, position: Default::default(), append: fdflags.contains(types::Fdflags::APPEND), @@ -2282,7 +2282,7 @@ impl< if status >= 126 { return anyhow::Error::msg("exit with invalid exit status outside of [0..126)"); } - crate::preview2::I32Exit(status as i32).into() + crate::I32Exit(status as i32).into() } #[instrument(skip(self))] diff --git a/crates/wasi/src/preview2/command.rs b/crates/wasi/src/preview2/command.rs deleted file mode 100644 index 3a4683146b..0000000000 --- a/crates/wasi/src/preview2/command.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::preview2::WasiView; - -wasmtime::component::bindgen!({ - world: "wasi:cli/command", - tracing: true, - async: true, - with: { - "wasi:filesystem/types": crate::preview2::bindings::filesystem::types, - "wasi:filesystem/preopens": crate::preview2::bindings::filesystem::preopens, - "wasi:sockets/tcp": crate::preview2::bindings::sockets::tcp, - "wasi:clocks/monotonic_clock": crate::preview2::bindings::clocks::monotonic_clock, - "wasi:io/poll": crate::preview2::bindings::io::poll, - "wasi:io/streams": crate::preview2::bindings::io::streams, - "wasi:clocks/wall_clock": crate::preview2::bindings::clocks::wall_clock, - "wasi:random/random": crate::preview2::bindings::random::random, - "wasi:cli/environment": crate::preview2::bindings::cli::environment, - "wasi:cli/exit": crate::preview2::bindings::cli::exit, - "wasi:cli/stdin": crate::preview2::bindings::cli::stdin, - "wasi:cli/stdout": crate::preview2::bindings::cli::stdout, - "wasi:cli/stderr": crate::preview2::bindings::cli::stderr, - "wasi:cli/terminal-input": crate::preview2::bindings::cli::terminal_input, - "wasi:cli/terminal-output": crate::preview2::bindings::cli::terminal_output, - "wasi:cli/terminal-stdin": crate::preview2::bindings::cli::terminal_stdin, - "wasi:cli/terminal-stdout": crate::preview2::bindings::cli::terminal_stdout, - "wasi:cli/terminal-stderr": crate::preview2::bindings::cli::terminal_stderr, - }, -}); - -pub fn add_to_linker(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> { - crate::preview2::bindings::clocks::wall_clock::add_to_linker(l, |t| t)?; - crate::preview2::bindings::clocks::monotonic_clock::add_to_linker(l, |t| t)?; - crate::preview2::bindings::filesystem::types::add_to_linker(l, |t| t)?; - crate::preview2::bindings::filesystem::preopens::add_to_linker(l, |t| t)?; - crate::preview2::bindings::io::error::add_to_linker(l, |t| t)?; - crate::preview2::bindings::io::poll::add_to_linker(l, |t| t)?; - crate::preview2::bindings::io::streams::add_to_linker(l, |t| t)?; - crate::preview2::bindings::random::random::add_to_linker(l, |t| t)?; - crate::preview2::bindings::random::insecure::add_to_linker(l, |t| t)?; - crate::preview2::bindings::random::insecure_seed::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::exit::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::environment::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::stdin::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::stdout::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::stderr::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_input::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_output::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_stdin::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_stdout::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_stderr::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::tcp::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::tcp_create_socket::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::udp::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::udp_create_socket::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::instance_network::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::network::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::ip_name_lookup::add_to_linker(l, |t| t)?; - Ok(()) -} - -pub mod sync { - use crate::preview2::WasiView; - - wasmtime::component::bindgen!({ - world: "wasi:cli/command", - tracing: true, - async: false, - with: { - "wasi:filesystem/types": crate::preview2::bindings::sync_io::filesystem::types, - "wasi:filesystem/preopens": crate::preview2::bindings::filesystem::preopens, - "wasi:sockets/tcp": crate::preview2::bindings::sockets::tcp, - "wasi:sockets/udp": crate::preview2::bindings::sockets::udp, - "wasi:clocks/monotonic_clock": crate::preview2::bindings::clocks::monotonic_clock, - "wasi:io/poll": crate::preview2::bindings::sync_io::io::poll, - "wasi:io/streams": crate::preview2::bindings::sync_io::io::streams, - "wasi:clocks/wall_clock": crate::preview2::bindings::clocks::wall_clock, - "wasi:random/random": crate::preview2::bindings::random::random, - "wasi:cli/environment": crate::preview2::bindings::cli::environment, - "wasi:cli/exit": crate::preview2::bindings::cli::exit, - "wasi:cli/stdin": crate::preview2::bindings::cli::stdin, - "wasi:cli/stdout": crate::preview2::bindings::cli::stdout, - "wasi:cli/stderr": crate::preview2::bindings::cli::stderr, - "wasi:cli/terminal-input": crate::preview2::bindings::cli::terminal_input, - "wasi:cli/terminal-output": crate::preview2::bindings::cli::terminal_output, - "wasi:cli/terminal-stdin": crate::preview2::bindings::cli::terminal_stdin, - "wasi:cli/terminal-stdout": crate::preview2::bindings::cli::terminal_stdout, - "wasi:cli/terminal-stderr": crate::preview2::bindings::cli::terminal_stderr, - }, - }); - - pub fn add_to_linker( - l: &mut wasmtime::component::Linker, - ) -> anyhow::Result<()> { - crate::preview2::bindings::clocks::wall_clock::add_to_linker(l, |t| t)?; - crate::preview2::bindings::clocks::monotonic_clock::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sync_io::filesystem::types::add_to_linker(l, |t| t)?; - crate::preview2::bindings::filesystem::preopens::add_to_linker(l, |t| t)?; - crate::preview2::bindings::io::error::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sync_io::io::poll::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sync_io::io::streams::add_to_linker(l, |t| t)?; - crate::preview2::bindings::random::random::add_to_linker(l, |t| t)?; - crate::preview2::bindings::random::insecure::add_to_linker(l, |t| t)?; - crate::preview2::bindings::random::insecure_seed::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::exit::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::environment::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::stdin::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::stdout::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::stderr::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_input::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_output::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_stdin::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_stdout::add_to_linker(l, |t| t)?; - crate::preview2::bindings::cli::terminal_stderr::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::tcp::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::tcp_create_socket::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::udp::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::udp_create_socket::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::instance_network::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::network::add_to_linker(l, |t| t)?; - crate::preview2::bindings::sockets::ip_name_lookup::add_to_linker(l, |t| t)?; - Ok(()) - } -} diff --git a/crates/wasi/src/preview2/mod.rs b/crates/wasi/src/preview2/mod.rs deleted file mode 100644 index 1608750436..0000000000 --- a/crates/wasi/src/preview2/mod.rs +++ /dev/null @@ -1,327 +0,0 @@ -//! # Wasmtime's WASI Preview 2 Implementation -//! -//! Welcome to the (new!) WASI implementation from the Wasmtime team. The goal -//! of this implementation is to support WASI Preview 2 via the Component -//! Model, as well as to provide legacy Preview 1 host support with an adapter -//! that is implemented in terms of the Preview 2 interfaces. -//! -//! Presently, this crate is experimental. We don't yet recommend you use it -//! in production. Specifically: -//! * the wit files in tree describing preview 2 are not faithful to the -//! standards repos -//! -//! Once these issues are resolved, we expect to move this namespace up to the -//! root of the wasmtime-wasi crate, and move its other exports underneath a -//! `pub mod legacy` with an off-by-default feature flag, and after 2 -//! releases, retire and remove that code from our tree. - -use std::future::Future; -use std::pin::Pin; -use std::task::{Context, Poll}; - -mod clocks; -pub mod command; -mod ctx; -mod error; -mod filesystem; -mod host; -mod ip_name_lookup; -mod network; -pub mod pipe; -mod poll; -#[cfg(feature = "preview1-on-preview2")] -pub mod preview0; -#[cfg(feature = "preview1-on-preview2")] -pub mod preview1; -mod random; -mod stdio; -mod stream; -mod tcp; -mod udp; -mod write_stream; - -pub use self::clocks::{HostMonotonicClock, HostWallClock}; -pub use self::ctx::{WasiCtx, WasiCtxBuilder, WasiView}; -pub use self::error::{I32Exit, TrappableError}; -pub use self::filesystem::{DirPerms, FilePerms, FsError, FsResult}; -pub use self::network::{Network, SocketError, SocketResult}; -pub use self::poll::{subscribe, ClosureFuture, MakeFuture, Pollable, PollableFuture, Subscribe}; -pub use self::random::{thread_rng, Deterministic}; -pub use self::stdio::{ - stderr, stdin, stdout, IsATTY, Stderr, Stdin, StdinStream, Stdout, StdoutStream, -}; -pub use self::stream::{ - HostInputStream, HostOutputStream, InputStream, OutputStream, StreamError, StreamResult, -}; -pub use cap_fs_ext::SystemTimeSpec; -pub use cap_rand::RngCore; -pub use wasmtime::component::{ResourceTable, ResourceTableError}; - -pub mod bindings { - // Generate traits for synchronous bindings. - // - // Note that this is only done for interfaces which can block, or those which - // have some functions in `only_imports` below for being async. - pub mod sync_io { - pub(crate) mod _internal { - use crate::preview2::{FsError, StreamError}; - - wasmtime::component::bindgen!({ - path: "wit", - interfaces: " - import wasi:io/poll@0.2.0; - import wasi:io/streams@0.2.0; - import wasi:filesystem/types@0.2.0; - ", - tracing: true, - trappable_error_type: { - "wasi:io/streams/stream-error" => StreamError, - "wasi:filesystem/types/error-code" => FsError, - }, - with: { - "wasi:clocks/wall-clock": crate::preview2::bindings::clocks::wall_clock, - "wasi:filesystem/types/descriptor": super::super::filesystem::types::Descriptor, - "wasi:filesystem/types/directory-entry-stream": super::super::filesystem::types::DirectoryEntryStream, - "wasi:io/poll/pollable": super::super::io::poll::Pollable, - "wasi:io/streams/input-stream": super::super::io::streams::InputStream, - "wasi:io/streams/output-stream": super::super::io::streams::OutputStream, - "wasi:io/error/error": super::super::io::error::Error, - } - }); - } - pub use self::_internal::wasi::{filesystem, io}; - } - - wasmtime::component::bindgen!({ - path: "wit", - world: "wasi:cli/imports", - tracing: 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: [ - "[method]descriptor.access-at", - "[method]descriptor.advise", - "[method]descriptor.change-directory-permissions-at", - "[method]descriptor.change-file-permissions-at", - "[method]descriptor.create-directory-at", - "[method]descriptor.get-flags", - "[method]descriptor.get-type", - "[method]descriptor.is-same-object", - "[method]descriptor.link-at", - "[method]descriptor.lock-exclusive", - "[method]descriptor.lock-shared", - "[method]descriptor.metadata-hash", - "[method]descriptor.metadata-hash-at", - "[method]descriptor.open-at", - "[method]descriptor.read", - "[method]descriptor.read-directory", - "[method]descriptor.readlink-at", - "[method]descriptor.remove-directory-at", - "[method]descriptor.rename-at", - "[method]descriptor.set-size", - "[method]descriptor.set-times", - "[method]descriptor.set-times-at", - "[method]descriptor.stat", - "[method]descriptor.stat-at", - "[method]descriptor.symlink-at", - "[method]descriptor.sync", - "[method]descriptor.sync-data", - "[method]descriptor.try-lock-exclusive", - "[method]descriptor.try-lock-shared", - "[method]descriptor.unlink-file-at", - "[method]descriptor.unlock", - "[method]descriptor.write", - "[method]input-stream.read", - "[method]input-stream.blocking-read", - "[method]input-stream.blocking-skip", - "[method]input-stream.skip", - "[method]output-stream.forward", - "[method]output-stream.splice", - "[method]output-stream.blocking-splice", - "[method]output-stream.blocking-flush", - "[method]output-stream.blocking-write", - "[method]output-stream.blocking-write-and-flush", - "[method]output-stream.blocking-write-zeroes-and-flush", - "[method]directory-entry-stream.read-directory-entry", - "poll", - "[method]pollable.block", - "[method]pollable.ready", - ], - }, - trappable_error_type: { - "wasi:io/streams/stream-error" => crate::preview2::StreamError, - "wasi:filesystem/types/error-code" => crate::preview2::FsError, - "wasi:sockets/network/error-code" => crate::preview2::SocketError, - }, - with: { - "wasi:sockets/network/network": super::network::Network, - "wasi:sockets/tcp/tcp-socket": super::tcp::TcpSocket, - "wasi:sockets/udp/udp-socket": super::udp::UdpSocket, - "wasi:sockets/udp/incoming-datagram-stream": super::udp::IncomingDatagramStream, - "wasi:sockets/udp/outgoing-datagram-stream": super::udp::OutgoingDatagramStream, - "wasi:sockets/ip-name-lookup/resolve-address-stream": super::ip_name_lookup::ResolveAddressStream, - "wasi:filesystem/types/directory-entry-stream": super::filesystem::ReaddirIterator, - "wasi:filesystem/types/descriptor": super::filesystem::Descriptor, - "wasi:io/streams/input-stream": super::stream::InputStream, - "wasi:io/streams/output-stream": super::stream::OutputStream, - "wasi:io/error/error": super::stream::Error, - "wasi:io/poll/pollable": super::poll::Pollable, - "wasi:cli/terminal-input/terminal-input": super::stdio::TerminalInput, - "wasi:cli/terminal-output/terminal-output": super::stdio::TerminalOutput, - }, - }); - - pub use wasi::*; -} - -pub(crate) static RUNTIME: once_cell::sync::Lazy = - once_cell::sync::Lazy::new(|| { - tokio::runtime::Builder::new_current_thread() - .enable_time() - .enable_io() - .build() - .unwrap() - }); - -pub struct AbortOnDropJoinHandle(tokio::task::JoinHandle); -impl Drop for AbortOnDropJoinHandle { - fn drop(&mut self) { - self.0.abort() - } -} -impl std::ops::Deref for AbortOnDropJoinHandle { - type Target = tokio::task::JoinHandle; - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl std::ops::DerefMut for AbortOnDropJoinHandle { - fn deref_mut(&mut self) -> &mut tokio::task::JoinHandle { - &mut self.0 - } -} -impl From> for AbortOnDropJoinHandle { - fn from(jh: tokio::task::JoinHandle) -> Self { - AbortOnDropJoinHandle(jh) - } -} -impl Future for AbortOnDropJoinHandle { - type Output = T; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match Pin::new(&mut self.as_mut().0).poll(cx) { - Poll::Pending => Poll::Pending, - Poll::Ready(r) => Poll::Ready(r.expect("child task panicked")), - } - } -} - -pub fn spawn(f: F) -> AbortOnDropJoinHandle -where - F: Future + Send + 'static, - F::Output: Send + 'static, -{ - let j = with_ambient_tokio_runtime(|| tokio::task::spawn(f)); - AbortOnDropJoinHandle(j) -} - -pub fn spawn_blocking(f: F) -> AbortOnDropJoinHandle -where - F: FnOnce() -> R + Send + 'static, - R: Send + 'static, -{ - let j = with_ambient_tokio_runtime(|| tokio::task::spawn_blocking(f)); - AbortOnDropJoinHandle(j) -} - -pub fn in_tokio(f: F) -> F::Output { - match tokio::runtime::Handle::try_current() { - Ok(h) => { - let _enter = h.enter(); - h.block_on(f) - } - // The `yield_now` here is non-obvious and if you're reading this - // you're likely curious about why it's here. This is currently required - // to get some features of "sync mode" working correctly, such as with - // the CLI. To illustrate why this is required, consider a program - // organized as: - // - // * A program has a `pollable` that it's waiting on. - // * This `pollable` is always ready . - // * Actually making the corresponding operation ready, however, - // requires some background work on Tokio's part. - // * The program is looping on "wait for readiness" coupled with - // performing the operation. - // - // In this situation this program ends up infinitely looping in waiting - // for pollables. The reason appears to be that when we enter the tokio - // runtime here it doesn't necessary yield to background work because - // the provided future `f` is ready immediately. The future `f` will run - // through the list of pollables and determine one of them is ready. - // - // Historically this happened with UDP sockets. A test send a datagram - // from one socket to another and the other socket infinitely didn't - // receive the data. This appeared to be because the server socket was - // waiting on `READABLE | WRITABLE` (which is itself a bug but ignore - // that) and the socket was currently in the "writable" state but never - // ended up receiving a notification for the "readable" state. Moving - // the socket to "readable" would require Tokio to perform some - // background work via epoll/kqueue/handle events but if the future - // provided here is always ready, then that never happened. - // - // Thus the `yield_now()` is an attempt to force Tokio to go do some - // background work eventually and look at new interest masks for - // example. This is a bit of a kludge but everything's already a bit - // wonky in synchronous mode anyway. Note that this is hypothesized to - // not be an issue in async mode because async mode typically has the - // Tokio runtime in a separate thread or otherwise participating in a - // larger application, it's only here in synchronous mode where we - // effectively own the runtime that we need some special care. - Err(_) => { - let _enter = RUNTIME.enter(); - RUNTIME.block_on(async move { - tokio::task::yield_now().await; - f.await - }) - } - } -} - -/// Executes the closure `f` with an "ambient Tokio runtime" which basically -/// means that if code in `f` tries to get a runtime `Handle` it'll succeed. -/// -/// If a `Handle` is already available, e.g. in async contexts, then `f` is run -/// immediately. Otherwise for synchronous contexts this crate's fallback -/// runtime is configured and then `f` is executed. -pub fn with_ambient_tokio_runtime(f: impl FnOnce() -> R) -> R { - match tokio::runtime::Handle::try_current() { - Ok(_) => f(), - Err(_) => { - let _enter = RUNTIME.enter(); - f() - } - } -} - -/// Attempts to get the result of a `future`. -/// -/// This function does not block and will poll the provided future once. If the -/// result is here then `Some` is returned, otherwise `None` is returned. -/// -/// Note that by polling `future` this means that `future` must be re-polled -/// later if it's to wake up a task. -pub fn poll_noop(future: Pin<&mut F>) -> Option -where - F: Future, -{ - let mut task = Context::from_waker(futures::task::noop_waker_ref()); - match future.poll(&mut task) { - Poll::Ready(result) => Some(result), - Poll::Pending => None, - } -} diff --git a/crates/wasi/src/preview2/random.rs b/crates/wasi/src/random.rs similarity index 100% rename from crates/wasi/src/preview2/random.rs rename to crates/wasi/src/random.rs diff --git a/crates/wasi/src/preview2/stdio.rs b/crates/wasi/src/stdio.rs similarity index 97% rename from crates/wasi/src/preview2/stdio.rs rename to crates/wasi/src/stdio.rs index 193f7c3dcf..5c6b191eb0 100644 --- a/crates/wasi/src/preview2/stdio.rs +++ b/crates/wasi/src/stdio.rs @@ -1,12 +1,10 @@ -use crate::preview2::bindings::cli::{ +use crate::bindings::cli::{ stderr, stdin, stdout, terminal_input, terminal_output, terminal_stderr, terminal_stdin, terminal_stdout, }; -use crate::preview2::bindings::io::streams; -use crate::preview2::pipe; -use crate::preview2::{ - HostInputStream, HostOutputStream, StreamError, StreamResult, Subscribe, WasiView, -}; +use crate::bindings::io::streams; +use crate::pipe; +use crate::{HostInputStream, HostOutputStream, StreamError, StreamResult, Subscribe, WasiView}; use bytes::Bytes; use std::io::IsTerminal; use wasmtime::component::Resource; diff --git a/crates/wasi/src/preview2/stdio/worker_thread_stdin.rs b/crates/wasi/src/stdio/worker_thread_stdin.rs similarity index 97% rename from crates/wasi/src/preview2/stdio/worker_thread_stdin.rs rename to crates/wasi/src/stdio/worker_thread_stdin.rs index cb2f50f2c6..fbde369b37 100644 --- a/crates/wasi/src/preview2/stdio/worker_thread_stdin.rs +++ b/crates/wasi/src/stdio/worker_thread_stdin.rs @@ -23,9 +23,9 @@ //! This module is one that's likely to change over time though as new systems //! are encountered along with preexisting bugs. -use crate::preview2::poll::Subscribe; -use crate::preview2::stdio::StdinStream; -use crate::preview2::{HostInputStream, StreamError}; +use crate::poll::Subscribe; +use crate::stdio::StdinStream; +use crate::{HostInputStream, StreamError}; use bytes::{Bytes, BytesMut}; use std::io::{IsTerminal, Read}; use std::mem; diff --git a/crates/wasi/src/preview2/stream.rs b/crates/wasi/src/stream.rs similarity index 98% rename from crates/wasi/src/preview2/stream.rs rename to crates/wasi/src/stream.rs index bf2ce502ba..4fcb4c4655 100644 --- a/crates/wasi/src/preview2/stream.rs +++ b/crates/wasi/src/stream.rs @@ -1,5 +1,5 @@ -use crate::preview2::filesystem::FileInputStream; -use crate::preview2::poll::Subscribe; +use crate::filesystem::FileInputStream; +use crate::poll::Subscribe; use anyhow::Result; use bytes::Bytes; diff --git a/crates/wasi/src/preview2/tcp.rs b/crates/wasi/src/tcp.rs similarity index 98% rename from crates/wasi/src/preview2/tcp.rs rename to crates/wasi/src/tcp.rs index 0b27aa3b55..468bbb75c3 100644 --- a/crates/wasi/src/preview2/tcp.rs +++ b/crates/wasi/src/tcp.rs @@ -2,7 +2,7 @@ use super::network::SocketAddressFamily; use super::{ with_ambient_tokio_runtime, HostInputStream, HostOutputStream, SocketResult, StreamError, }; -use crate::preview2::{AbortOnDropJoinHandle, Subscribe}; +use crate::{AbortOnDropJoinHandle, Subscribe}; use anyhow::{Error, Result}; use cap_net_ext::AddressFamily; use futures::Future; @@ -164,7 +164,7 @@ impl TcpWriteStream { assert!(matches!(self.last_write, LastWrite::Done)); let stream = self.stream.clone(); - self.last_write = LastWrite::Waiting(crate::preview2::spawn(async move { + self.last_write = LastWrite::Waiting(crate::spawn(async move { // Note: we are not using the AsyncWrite impl here, and instead using the TcpStream // primitive try_write, which goes directly to attempt a write with mio. This has // two advantages: 1. this operation takes a &TcpStream instead of a &mut TcpStream @@ -296,7 +296,7 @@ impl TcpSocket { } pub(crate) fn as_std_view(&self) -> SocketResult> { - use crate::preview2::bindings::sockets::network::ErrorCode; + use crate::bindings::sockets::network::ErrorCode; match &self.tcp_state { TcpState::Default(socket) | TcpState::Bound(socket) => { diff --git a/crates/wasi/src/preview2/udp.rs b/crates/wasi/src/udp.rs similarity index 96% rename from crates/wasi/src/preview2/udp.rs rename to crates/wasi/src/udp.rs index e6a5269a80..bb9819f2ed 100644 --- a/crates/wasi/src/preview2/udp.rs +++ b/crates/wasi/src/udp.rs @@ -1,6 +1,6 @@ -use crate::preview2::host::network::util; -use crate::preview2::poll::Subscribe; -use crate::preview2::with_ambient_tokio_runtime; +use crate::host::network::util; +use crate::poll::Subscribe; +use crate::with_ambient_tokio_runtime; use async_trait::async_trait; use cap_net_ext::{AddressFamily, Blocking}; use io_lifetimes::raw::{FromRawSocketlike, IntoRawSocketlike}; diff --git a/crates/wasi/src/preview2/write_stream.rs b/crates/wasi/src/write_stream.rs similarity index 96% rename from crates/wasi/src/preview2/write_stream.rs rename to crates/wasi/src/write_stream.rs index 79f3815376..eb76e2c3b6 100644 --- a/crates/wasi/src/preview2/write_stream.rs +++ b/crates/wasi/src/write_stream.rs @@ -1,4 +1,4 @@ -use crate::preview2::{HostOutputStream, StreamError, Subscribe}; +use crate::{HostOutputStream, StreamError, Subscribe}; use anyhow::anyhow; use bytes::Bytes; use std::sync::{Arc, Mutex}; @@ -139,7 +139,7 @@ impl Worker { /// Provides a [`HostOutputStream`] impl from a [`tokio::io::AsyncWrite`] impl pub struct AsyncWriteStream { worker: Arc, - _join_handle: crate::preview2::AbortOnDropJoinHandle<()>, + _join_handle: crate::AbortOnDropJoinHandle<()>, } impl AsyncWriteStream { @@ -152,7 +152,7 @@ impl AsyncWriteStream { let worker = Arc::new(Worker::new(write_budget)); let w = Arc::clone(&worker); - let join_handle = crate::preview2::spawn(async move { w.work(writer).await }); + let join_handle = crate::spawn(async move { w.work(writer).await }); AsyncWriteStream { worker, diff --git a/crates/wasi/tests/all/api.rs b/crates/wasi/tests/all/api.rs index 0da9c78366..2fc5946979 100644 --- a/crates/wasi/tests/all/api.rs +++ b/crates/wasi/tests/all/api.rs @@ -6,11 +6,10 @@ use std::sync::Mutex; use std::time::Duration; use wasmtime::component::{Component, Linker, ResourceTable}; use wasmtime::{Config, Engine, Store}; -use wasmtime_wasi::preview2::bindings::wasi::clocks::wall_clock; -use wasmtime_wasi::preview2::bindings::wasi::filesystem::types as filesystem; -use wasmtime_wasi::preview2::command::{add_to_linker, Command}; -use wasmtime_wasi::preview2::{ - self, DirPerms, FilePerms, HostMonotonicClock, HostWallClock, WasiCtx, WasiCtxBuilder, WasiView, +use wasmtime_wasi::{ + bindings::wasi::{clocks::wall_clock, filesystem::types as filesystem}, + command::{add_to_linker, Command}, + DirPerms, FilePerms, HostMonotonicClock, HostWallClock, WasiCtx, WasiCtxBuilder, WasiView, }; struct CommandCtx { @@ -127,19 +126,19 @@ wasmtime::component::bindgen!({ world: "test-reactor", async: true, with: { - "wasi:io/streams": preview2::bindings::io::streams, - "wasi:filesystem/types": preview2::bindings::filesystem::types, - "wasi:filesystem/preopens": preview2::bindings::filesystem::preopens, - "wasi:cli/environment": preview2::bindings::cli::environment, - "wasi:cli/exit": preview2::bindings::cli::exit, - "wasi:cli/stdin": preview2::bindings::cli::stdin, - "wasi:cli/stdout": preview2::bindings::cli::stdout, - "wasi:cli/stderr": preview2::bindings::cli::stderr, - "wasi:cli/terminal_input": preview2::bindings::cli::terminal_input, - "wasi:cli/terminal_output": preview2::bindings::cli::terminal_output, - "wasi:cli/terminal_stdin": preview2::bindings::cli::terminal_stdin, - "wasi:cli/terminal_stdout": preview2::bindings::cli::terminal_stdout, - "wasi:cli/terminal_stderr": preview2::bindings::cli::terminal_stderr, + "wasi:io/streams": wasmtime_wasi::bindings::io::streams, + "wasi:filesystem/types": wasmtime_wasi::bindings::filesystem::types, + "wasi:filesystem/preopens": wasmtime_wasi::bindings::filesystem::preopens, + "wasi:cli/environment": wasmtime_wasi::bindings::cli::environment, + "wasi:cli/exit": wasmtime_wasi::bindings::cli::exit, + "wasi:cli/stdin": wasmtime_wasi::bindings::cli::stdin, + "wasi:cli/stdout": wasmtime_wasi::bindings::cli::stdout, + "wasi:cli/stderr": wasmtime_wasi::bindings::cli::stderr, + "wasi:cli/terminal_input": wasmtime_wasi::bindings::cli::terminal_input, + "wasi:cli/terminal_output": wasmtime_wasi::bindings::cli::terminal_output, + "wasi:cli/terminal_stdin": wasmtime_wasi::bindings::cli::terminal_stdin, + "wasi:cli/terminal_stdout": wasmtime_wasi::bindings::cli::terminal_stdout, + "wasi:cli/terminal_stderr": wasmtime_wasi::bindings::cli::terminal_stderr, }, ownership: Borrowing { duplicate_if_necessary: false @@ -176,8 +175,8 @@ async fn api_reactor() -> Result<()> { // `host` and `wasi-common` crate. // Note, this works because of the add_to_linker invocations using the // `host` crate for `streams`, not because of `with` in the bindgen macro. - let writepipe = preview2::pipe::MemoryOutputPipe::new(4096); - let stream: preview2::OutputStream = Box::new(writepipe.clone()); + let writepipe = wasmtime_wasi::pipe::MemoryOutputPipe::new(4096); + let stream: wasmtime_wasi::OutputStream = Box::new(writepipe.clone()); let table_ix = store.data_mut().table().push(stream)?; let r = reactor.call_write_strings_to(&mut store, table_ix).await?; assert_eq!(r, Ok(())); diff --git a/crates/wasi/tests/all/async_.rs b/crates/wasi/tests/all/async_.rs index 063a23b037..0ba7bce170 100644 --- a/crates/wasi/tests/all/async_.rs +++ b/crates/wasi/tests/all/async_.rs @@ -1,7 +1,7 @@ use super::*; use std::path::Path; use test_programs_artifacts::*; -use wasmtime_wasi::preview2::command::{add_to_linker, Command}; +use wasmtime_wasi::command::{add_to_linker, Command}; async fn run(path: &str, inherit_stdio: bool) -> Result<()> { let path = Path::new(path); diff --git a/crates/wasi/tests/all/main.rs b/crates/wasi/tests/all/main.rs index 7be20730f4..ea1b2e8721 100644 --- a/crates/wasi/tests/all/main.rs +++ b/crates/wasi/tests/all/main.rs @@ -4,7 +4,7 @@ use wasmtime::{ component::{Component, Linker, ResourceTable}, Config, Engine, Store, }; -use wasmtime_wasi::preview2::{ +use wasmtime_wasi::{ pipe::MemoryOutputPipe, preview1::{WasiPreview1Adapter, WasiPreview1View}, DirPerms, FilePerms, WasiCtx, WasiCtxBuilder, WasiView, diff --git a/crates/wasi/tests/all/preview1.rs b/crates/wasi/tests/all/preview1.rs index dcfcb0041f..7dd8f2db57 100644 --- a/crates/wasi/tests/all/preview1.rs +++ b/crates/wasi/tests/all/preview1.rs @@ -2,7 +2,7 @@ use super::*; use std::path::Path; use test_programs_artifacts::*; use wasmtime::{Linker, Module}; -use wasmtime_wasi::preview2::preview1::add_to_linker_async; +use wasmtime_wasi::preview1::add_to_linker_async; async fn run(path: &str, inherit_stdio: bool) -> Result<()> { let path = Path::new(path); diff --git a/crates/wasi/tests/all/sync.rs b/crates/wasi/tests/all/sync.rs index d0446c4445..957724edde 100644 --- a/crates/wasi/tests/all/sync.rs +++ b/crates/wasi/tests/all/sync.rs @@ -1,7 +1,7 @@ use super::*; use std::path::Path; use test_programs_artifacts::*; -use wasmtime_wasi::preview2::command::sync::{add_to_linker, Command}; +use wasmtime_wasi::command::sync::{add_to_linker, Command}; fn run(path: &str, inherit_stdio: bool) -> Result<()> { let path = Path::new(path); diff --git a/crates/wasi/tests/process_stdin.rs b/crates/wasi/tests/process_stdin.rs index 5835335f3b..73e8ce4666 100644 --- a/crates/wasi/tests/process_stdin.rs +++ b/crates/wasi/tests/process_stdin.rs @@ -1,6 +1,6 @@ use std::io::{BufRead, Write}; use std::process::Command; -use wasmtime_wasi::preview2::{HostInputStream, Subscribe}; +use wasmtime_wasi::{HostInputStream, Subscribe}; const VAR_NAME: &str = "__CHILD_PROCESS"; @@ -35,7 +35,7 @@ fn main() { .block_on(async { 'task: loop { println!("child: creating stdin"); - let mut stdin = wasmtime_wasi::preview2::stdin(); + let mut stdin = wasmtime_wasi::stdin(); println!("child: checking that stdin is not ready"); assert!( diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4277fcdc64..9e2e049039 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -77,5 +77,5 @@ create_rust_test(multimemory) create_rust_test(serialize) create_rust_test(threads) create_rust_test(wasi) -create_rust_test(tokio wasmtime-wasi/tokio) +create_rust_test(tokio wasi-common/tokio) create_rust_test(component) diff --git a/examples/wasi-async/main.rs b/examples/wasi-async/main.rs index f99e543a99..87661cd249 100644 --- a/examples/wasi-async/main.rs +++ b/examples/wasi-async/main.rs @@ -9,30 +9,29 @@ You can execute this example with: use anyhow::Result; use wasmtime::{Config, Engine, Linker, Module, Store}; -use wasmtime_wasi::preview2; struct WasiHostCtx { - preview2_ctx: preview2::WasiCtx, + preview2_ctx: wasmtime_wasi::WasiCtx, preview2_table: wasmtime::component::ResourceTable, - preview1_adapter: preview2::preview1::WasiPreview1Adapter, + preview1_adapter: wasmtime_wasi::preview1::WasiPreview1Adapter, } -impl preview2::WasiView for WasiHostCtx { +impl wasmtime_wasi::WasiView for WasiHostCtx { fn table(&mut self) -> &mut wasmtime::component::ResourceTable { &mut self.preview2_table } - fn ctx(&mut self) -> &mut preview2::WasiCtx { + fn ctx(&mut self) -> &mut wasmtime_wasi::WasiCtx { &mut self.preview2_ctx } } -impl preview2::preview1::WasiPreview1View for WasiHostCtx { - fn adapter(&self) -> &preview2::preview1::WasiPreview1Adapter { +impl wasmtime_wasi::preview1::WasiPreview1View for WasiHostCtx { + fn adapter(&self) -> &wasmtime_wasi::preview1::WasiPreview1Adapter { &self.preview1_adapter } - fn adapter_mut(&mut self) -> &mut preview2::preview1::WasiPreview1Adapter { + fn adapter_mut(&mut self) -> &mut wasmtime_wasi::preview1::WasiPreview1Adapter { &mut self.preview1_adapter } } @@ -47,15 +46,15 @@ async fn main() -> Result<()> { // Add the WASI preview1 API to the linker (will be implemented in terms of // the preview2 API) let mut linker: Linker = Linker::new(&engine); - preview2::preview1::add_to_linker_async(&mut linker)?; + wasmtime_wasi::preview1::add_to_linker_async(&mut linker)?; // Add capabilities (e.g. filesystem access) to the WASI preview2 context here. - let wasi_ctx = preview2::WasiCtxBuilder::new().inherit_stdio().build(); + let wasi_ctx = wasmtime_wasi::WasiCtxBuilder::new().inherit_stdio().build(); let host_ctx = WasiHostCtx { preview2_ctx: wasi_ctx, - preview2_table: preview2::ResourceTable::new(), - preview1_adapter: preview2::preview1::WasiPreview1Adapter::new(), + preview2_table: wasmtime::component::ResourceTable::new(), + preview1_adapter: wasmtime_wasi::preview1::WasiPreview1Adapter::new(), }; let mut store: Store = Store::new(&engine, host_ctx); diff --git a/src/commands/run.rs b/src/commands/run.rs index bc0230ad93..aabfe199bd 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -15,7 +15,6 @@ use std::sync::{Arc, Mutex}; use std::thread; use wasi_common::sync::{ambient_authority, Dir, TcpListener, WasiCtxBuilder}; use wasmtime::{Engine, Func, Module, Store, StoreLimits, Val, ValType}; -use wasmtime_wasi::preview2; #[cfg(feature = "wasi-nn")] use wasmtime_wasi_nn::WasiNnCtx; @@ -226,7 +225,7 @@ impl RunCommand { return Err(wasi_common::maybe_exit_on_error(e)); } else if store.data().preview2_ctx.is_some() { if let Some(exit) = e - .downcast_ref::() + .downcast_ref::() .map(|c| c.process_exit_code()) { std::process::exit(exit); @@ -474,8 +473,11 @@ impl RunCommand { let component = module.unwrap_component(); - let (command, _instance) = - preview2::command::sync::Command::instantiate(&mut *store, component, linker)?; + let (command, _instance) = wasmtime_wasi::command::sync::Command::instantiate( + &mut *store, + component, + linker, + )?; let result = command .wasi_cli_run() .call_run(&mut *store) @@ -486,7 +488,7 @@ impl RunCommand { // explicit exit here with status 1 if `Err(())` is returned. result.and_then(|wasm_result| match wasm_result { Ok(()) => Ok(()), - Err(()) => Err(wasmtime_wasi::preview2::I32Exit(1).into()), + Err(()) => Err(wasmtime_wasi::I32Exit(1).into()), }) } }; @@ -626,16 +628,16 @@ impl RunCommand { // default-disabled in the future. (Some(true), _) | (None, Some(false) | None) => { if self.run.common.wasi.preview0 != Some(false) { - preview2::preview0::add_to_linker_sync(linker)?; + wasmtime_wasi::preview0::add_to_linker_sync(linker)?; } - preview2::preview1::add_to_linker_sync(linker)?; + wasmtime_wasi::preview1::add_to_linker_sync(linker)?; self.set_preview2_ctx(store)?; } } } #[cfg(feature = "component-model")] CliLinker::Component(linker) => { - preview2::command::sync::add_to_linker(linker)?; + wasmtime_wasi::command::sync::add_to_linker(linker)?; self.set_preview2_ctx(store)?; } } @@ -767,7 +769,7 @@ impl RunCommand { } fn set_preview2_ctx(&self, store: &mut Store) -> Result<()> { - let mut builder = preview2::WasiCtxBuilder::new(); + let mut builder = wasmtime_wasi::WasiCtxBuilder::new(); builder.inherit_stdio().args(&self.compute_argv()?); for (key, value) in self.vars.iter() { @@ -789,8 +791,8 @@ impl RunCommand { for (name, dir) in self.compute_preopen_dirs()? { builder.preopened_dir( dir, - preview2::DirPerms::all(), - preview2::FilePerms::all(), + wasmtime_wasi::DirPerms::all(), + wasmtime_wasi::FilePerms::all(), name, ); } @@ -821,7 +823,7 @@ struct Host { // The Mutex is only needed to satisfy the Sync constraint but we never // actually perform any locking on it as we use Mutex::get_mut for every // access. - preview2_ctx: Option>>, + preview2_ctx: Option>>, // Resource table for preview2 if the `preview2_ctx` is in use, otherwise // "just" an empty table. @@ -830,7 +832,7 @@ struct Host { // State necessary for the preview1 implementation of WASI backed by the // preview2 host implementation. Only used with the `--preview2` flag right // now when running core modules. - preview2_adapter: Arc, + preview2_adapter: Arc, #[cfg(feature = "wasi-nn")] wasi_nn: Option>, @@ -843,30 +845,31 @@ struct Host { guest_profiler: Option>, } -impl preview2::WasiView for Host { +impl wasmtime_wasi::WasiView for Host { fn table(&mut self) -> &mut wasmtime::component::ResourceTable { Arc::get_mut(&mut self.preview2_table) - .expect("preview2 is not compatible with threads") + .expect("wasmtime_wasi is not compatible with threads") .get_mut() .unwrap() } - fn ctx(&mut self) -> &mut preview2::WasiCtx { + fn ctx(&mut self) -> &mut wasmtime_wasi::WasiCtx { let ctx = self.preview2_ctx.as_mut().unwrap(); Arc::get_mut(ctx) - .expect("preview2 is not compatible with threads") + .expect("wasmtime_wasi is not compatible with threads") .get_mut() .unwrap() } } -impl preview2::preview1::WasiPreview1View for Host { - fn adapter(&self) -> &preview2::preview1::WasiPreview1Adapter { +impl wasmtime_wasi::preview1::WasiPreview1View for Host { + fn adapter(&self) -> &wasmtime_wasi::preview1::WasiPreview1Adapter { &self.preview2_adapter } - fn adapter_mut(&mut self) -> &mut preview2::preview1::WasiPreview1Adapter { - Arc::get_mut(&mut self.preview2_adapter).expect("preview2 is not compatible with threads") + fn adapter_mut(&mut self) -> &mut wasmtime_wasi::preview1::WasiPreview1Adapter { + Arc::get_mut(&mut self.preview2_adapter) + .expect("wasmtime_wasi is not compatible with threads") } } @@ -874,7 +877,7 @@ impl preview2::preview1::WasiPreview1View for Host { impl wasmtime_wasi_http::types::WasiHttpView for Host { fn ctx(&mut self) -> &mut WasiHttpCtx { let ctx = self.wasi_http.as_mut().unwrap(); - Arc::get_mut(ctx).expect("preview2 is not compatible with threads") + Arc::get_mut(ctx).expect("wasmtime_wasi is not compatible with threads") } fn table(&mut self) -> &mut wasmtime::component::ResourceTable { diff --git a/src/commands/serve.rs b/src/commands/serve.rs index b05b182758..f11f6bc734 100644 --- a/src/commands/serve.rs +++ b/src/commands/serve.rs @@ -11,7 +11,7 @@ use std::{ }; use wasmtime::component::{InstancePre, Linker}; use wasmtime::{Engine, Store, StoreLimits}; -use wasmtime_wasi::preview2::{self, StreamError, StreamResult, WasiCtx, WasiCtxBuilder, WasiView}; +use wasmtime_wasi::{StreamError, StreamResult, WasiCtx, WasiCtxBuilder, WasiView}; use wasmtime_wasi_http::io::TokioIo; use wasmtime_wasi_http::{ bindings::http::types as http_types, body::HyperOutgoingBody, hyper_response_error, @@ -201,7 +201,7 @@ impl ServeCommand { // bindings which adds just those interfaces that the proxy interface // uses. if self.run.common.wasi.common == Some(true) { - preview2::command::add_to_linker(linker)?; + wasmtime_wasi::command::add_to_linker(linker)?; wasmtime_wasi_http::proxy::add_only_http_to_linker(linker)?; } else { wasmtime_wasi_http::proxy::add_to_linker(linker)?; @@ -478,8 +478,8 @@ struct LogStream { output: Output, } -impl preview2::StdoutStream for LogStream { - fn stream(&self) -> Box { +impl wasmtime_wasi::StdoutStream for LogStream { + fn stream(&self) -> Box { Box::new(self.clone()) } @@ -493,7 +493,7 @@ impl preview2::StdoutStream for LogStream { } } -impl preview2::HostOutputStream for LogStream { +impl wasmtime_wasi::HostOutputStream for LogStream { fn write(&mut self, bytes: bytes::Bytes) -> StreamResult<()> { let mut msg = Vec::new(); @@ -520,6 +520,6 @@ impl preview2::HostOutputStream for LogStream { } #[async_trait::async_trait] -impl preview2::Subscribe for LogStream { +impl wasmtime_wasi::Subscribe for LogStream { async fn ready(&mut self) {} }