//! # Wasmtime's WASIp2 Implementation1//!2//!3//! This module provides a Wasmtime host implementation of WASI 0.2 (aka WASIp24//! aka Preview 2) and WASI 0.1 (aka WASIp1 aka Preview 1). WASI is implemented5//! with the Rust crates [`tokio`] and [`cap-std`] primarily, meaning that6//! operations are implemented in terms of their native platform equivalents by7//! default.8//!9//! # WASIp2 interfaces10//!11//! This module contains implementations of the following interfaces:12//!13//! * [`wasi:cli/environment`]14//! * [`wasi:cli/exit`]15//! * [`wasi:cli/stderr`]16//! * [`wasi:cli/stdin`]17//! * [`wasi:cli/stdout`]18//! * [`wasi:cli/terminal-input`]19//! * [`wasi:cli/terminal-output`]20//! * [`wasi:cli/terminal-stderr`]21//! * [`wasi:cli/terminal-stdin`]22//! * [`wasi:cli/terminal-stdout`]23//! * [`wasi:clocks/monotonic-clock`]24//! * [`wasi:clocks/wall-clock`]25//! * [`wasi:filesystem/preopens`]26//! * [`wasi:filesystem/types`]27//! * [`wasi:random/insecure-seed`]28//! * [`wasi:random/insecure`]29//! * [`wasi:random/random`]30//! * [`wasi:sockets/instance-network`]31//! * [`wasi:sockets/ip-name-lookup`]32//! * [`wasi:sockets/network`]33//! * [`wasi:sockets/tcp-create-socket`]34//! * [`wasi:sockets/tcp`]35//! * [`wasi:sockets/udp-create-socket`]36//! * [`wasi:sockets/udp`]37//!38//! Most traits are implemented for [`WasiCtxView`] trait which provides39//! access to [`WasiCtx`] and [`ResourceTable`], which defines the configuration40//! for WASI and handle state. The [`WasiView`] trait is used to acquire and41//! construct a [`WasiCtxView`].42//!43//! The [`wasmtime-wasi-io`] crate contains implementations of the44//! following interfaces, and this module reuses those implementations:45//!46//! * [`wasi:io/error`]47//! * [`wasi:io/poll`]48//! * [`wasi:io/streams`]49//!50//! These traits are implemented directly for [`ResourceTable`]. All aspects of51//! `wasmtime-wasi-io` that are used by this module are re-exported. Unless you52//! are implementing other host functionality that needs to interact with the53//! WASI scheduler and don't want to use other functionality provided by54//! `wasmtime-wasi`, you don't need to take a direct dependency on55//! `wasmtime-wasi-io`.56//!57//! # Generated Bindings58//!59//! This module uses [`wasmtime::component::bindgen!`] to generate bindings for60//! all WASI interfaces. Raw bindings are available in the [`bindings`] submodule61//! of this module. Downstream users can either implement these traits themselves62//! or you can use the built-in implementations in this module for63//! `WasiImpl<T: WasiView>`.64//!65//! # The `WasiView` trait66//!67//! This module's implementation of WASI is done in terms of an implementation of68//! [`WasiView`]. This trait provides a "view" into WASI-related state that is69//! contained within a [`Store<T>`](wasmtime::Store).70//!71//! For all of the generated bindings in this module (Host traits),72//! implementations are provided looking like:73//!74//! ```75//! # use wasmtime_wasi::WasiCtxView;76//! # trait WasiView {}77//! # mod bindings { pub mod wasi { pub trait Host {} } }78//! impl bindings::wasi::Host for WasiCtxView<'_> {79//! // ...80//! }81//! ```82//!83//! where the [`WasiCtxView`] type comes from [`WasiView::ctx`] for the type84//! contained within the `Store<T>`. The [`add_to_linker_sync`] and85//! [`add_to_linker_async`] function then require that `T: WasiView` with86//! [`Linker<T>`](wasmtime::component::Linker).87//!88//! To implement the [`WasiView`] trait you will first select a89//! `T` to put in `Store<T>` (typically, by defining your own struct).90//! Somewhere within `T` you'll store:91//!92//! * [`ResourceTable`] - created through default constructors.93//! * [`WasiCtx`] - created through [`WasiCtxBuilder`].94//!95//! You'll then write an implementation of the [`WasiView`]96//! trait to access those items in your `T`. For example:97//! ```98//! use wasmtime::component::ResourceTable;99//! use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};100//!101//! struct MyCtx {102//! table: ResourceTable,103//! wasi: WasiCtx,104//! }105//!106//! impl WasiView for MyCtx {107//! fn ctx(&mut self) -> WasiCtxView<'_> {108//! WasiCtxView { ctx: &mut self.wasi, table: &mut self.table }109//! }110//! }111//! ```112//!113//! # Async and Sync114//!115//! All WASIp2 functions are blocking from WebAssembly's point of view: a116//! WebAssembly call into these functions returns only when they are complete.117//!118//! This module provides an implementation of those functions in the host, where119//! for some functions, it is appropriate to implement them using async Rust and120//! the Tokio executor. The host implementation still blocks WebAssembly, but it121//! does not block the host's thread. Synchronous wrappers are also provided for122//! all async implementations, which create a private Tokio executor.123//!124//! Users can choose between these modes of implementation using variants125//! of the add_to_linker functions:126//!127//! * For non-async users, use [`add_to_linker_sync`].128//! * For async users, use [`add_to_linker_async`].129//!130//! Note that bindings are generated once for async and once for sync. Most131//! interfaces do not change, however, so only interfaces with blocking132//! functions have bindings generated twice. Bindings are organized as:133//!134//! * [`bindings`] - default location of all bindings, blocking functions are135//! `async`136//! * [`bindings::sync`] - blocking interfaces have synchronous versions here.137//!138//! # Module-specific traits139//!140//! This module's default implementation of WASI bindings to native primitives141//! for the platform that it is compiled for. For example opening a TCP socket142//! uses the native platform to open a TCP socket (so long as [`WasiCtxBuilder`]143//! allows it). There are a few important traits, however, that are specific to144//! this module.145//!146//! * [`InputStream`] and [`OutputStream`] - these are the host traits147//! behind the WASI `input-stream` and `output-stream` types in the148//! `wasi:io/streams` interface. These enable embedders to build their own149//! custom stream and insert them into a [`ResourceTable`] (as a boxed trait150//! object, see [`DynInputStream`] and [`DynOutputStream`]) to be used from151//! wasm.152//!153//! * [`Pollable`] - this trait enables building arbitrary logic to get hooked154//! into a `pollable` resource from `wasi:io/poll`. A pollable resource is155//! created through the [`subscribe`] function.156//!157//! * [`HostWallClock`](crate::HostWallClock) and [`HostMonotonicClock`](crate::HostMonotonicClock) are used in conjunction with158//! [`WasiCtxBuilder::wall_clock`] and [`WasiCtxBuilder::monotonic_clock`] if159//! the defaults host's clock should not be used.160//!161//! * [`StdinStream`] and [`StdoutStream`] are used to provide custom162//! stdin/stdout streams if they're not inherited (or null, which is the163//! default).164//!165//! These traits enable embedders to customize small portions of WASI interfaces166//! provided while still providing all other interfaces.167//!168//! # Examples169//!170//! Usage of this module is done through a few steps to get everything hooked up:171//!172//! 1. First implement [`WasiView`] for your type which is the173//! `T` in `Store<T>`.174//! 2. Add WASI interfaces to a `wasmtime::component::Linker<T>`. This is either175//! done through top-level functions like [`add_to_linker_sync`] or through176//! individual `add_to_linker` functions in generated bindings throughout177//! this module.178//! 3. Create a [`WasiCtx`] for each `Store<T>` through [`WasiCtxBuilder`]. Each179//! WASI context is "null" or "empty" by default, so items must be explicitly180//! added to get accessed by wasm (such as env vars or program arguments).181//! 4. Use the previous `Linker<T>` to instantiate a `Component` within a182//! `Store<T>`.183//!184//! For examples see each of [`WasiView`], [`WasiCtx`], [`WasiCtxBuilder`],185//! [`add_to_linker_sync`], and [`bindings::Command`].186//!187//! [`wasmtime::component::bindgen!`]: https://docs.rs/wasmtime/latest/wasmtime/component/macro.bindgen.html188//! [`tokio`]: https://crates.io/crates/tokio189//! [`cap-std`]: https://crates.io/crates/cap-std190//! [`wasmtime-wasi-io`]: https://crates.io/crates/wasmtime-wasi-io191//! [`wasi:cli/environment`]: bindings::cli::environment::Host192//! [`wasi:cli/exit`]: bindings::cli::exit::Host193//! [`wasi:cli/stderr`]: bindings::cli::stderr::Host194//! [`wasi:cli/stdin`]: bindings::cli::stdin::Host195//! [`wasi:cli/stdout`]: bindings::cli::stdout::Host196//! [`wasi:cli/terminal-input`]: bindings::cli::terminal_input::Host197//! [`wasi:cli/terminal-output`]: bindings::cli::terminal_output::Host198//! [`wasi:cli/terminal-stdin`]: bindings::cli::terminal_stdin::Host199//! [`wasi:cli/terminal-stdout`]: bindings::cli::terminal_stdout::Host200//! [`wasi:cli/terminal-stderr`]: bindings::cli::terminal_stderr::Host201//! [`wasi:clocks/monotonic-clock`]: bindings::clocks::monotonic_clock::Host202//! [`wasi:clocks/wall-clock`]: bindings::clocks::wall_clock::Host203//! [`wasi:filesystem/preopens`]: bindings::filesystem::preopens::Host204//! [`wasi:filesystem/types`]: bindings::filesystem::types::Host205//! [`wasi:io/error`]: wasmtime_wasi_io::bindings::wasi::io::error::Host206//! [`wasi:io/poll`]: wasmtime_wasi_io::bindings::wasi::io::poll::Host207//! [`wasi:io/streams`]: wasmtime_wasi_io::bindings::wasi::io::streams::Host208//! [`wasi:random/insecure-seed`]: bindings::random::insecure_seed::Host209//! [`wasi:random/insecure`]: bindings::random::insecure::Host210//! [`wasi:random/random`]: bindings::random::random::Host211//! [`wasi:sockets/instance-network`]: bindings::sockets::instance_network::Host212//! [`wasi:sockets/ip-name-lookup`]: bindings::sockets::ip_name_lookup::Host213//! [`wasi:sockets/network`]: bindings::sockets::network::Host214//! [`wasi:sockets/tcp-create-socket`]: bindings::sockets::tcp_create_socket::Host215//! [`wasi:sockets/tcp`]: bindings::sockets::tcp::Host216//! [`wasi:sockets/udp-create-socket`]: bindings::sockets::udp_create_socket::Host217//! [`wasi:sockets/udp`]: bindings::sockets::udp::Host218//! [`ResourceTable`]: wasmtime::component::ResourceTable219//! [`WasiCtx`]: crate::WasiCtx220//! [`WasiCtxView`]: crate::WasiCtxView221//! [`WasiCtxBuilder`]: crate::WasiCtxBuilder222//! [`WasiCtxBuilder::wall_clock`]: crate::WasiCtxBuilder::wall_clock223//! [`WasiCtxBuilder::monotonic_clock`]: crate::WasiCtxBuilder::monotonic_clock224//! [`StdinStream`]: crate::cli::StdinStream225//! [`StdoutStream`]: crate::cli::StdoutStream226227use crate::WasiView;228use crate::cli::{WasiCli, WasiCliView as _};229use crate::clocks::{WasiClocks, WasiClocksView as _};230use crate::filesystem::{WasiFilesystem, WasiFilesystemView as _};231use crate::random::WasiRandom;232use crate::sockets::{WasiSockets, WasiSocketsView as _};233use wasmtime::component::{HasData, Linker, ResourceTable};234235pub mod bindings;236pub(crate) mod filesystem;237mod host;238mod ip_name_lookup;239mod network;240pub mod pipe;241mod poll;242mod stdio;243mod tcp;244mod udp;245mod write_stream;246247pub use self::filesystem::{FsError, FsResult, ReaddirIterator};248pub use self::network::{Network, SocketError, SocketResult};249pub use self::stdio::IsATTY;250pub(crate) use tcp::P2TcpStreamingState;251// These contents of wasmtime-wasi-io are re-exported by this module for compatibility:252// they were originally defined in this module before being factored out, and many253// users of this module depend on them at these names.254pub use wasmtime_wasi_io::poll::{DynFuture, DynPollable, MakeFuture, Pollable, subscribe};255pub use wasmtime_wasi_io::streams::{256DynInputStream, DynOutputStream, Error as IoError, InputStream, OutputStream, StreamError,257StreamResult,258};259260/// Add all WASI interfaces from this crate into the `linker` provided.261///262/// This function will add the `async` variant of all interfaces into the263/// [`Linker`] provided. For embeddings with async support disabled see264/// [`add_to_linker_sync`] instead.265///266/// This function will add all interfaces implemented by this crate to the267/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by268/// this crate.269///270/// # Example271///272/// ```273/// use wasmtime::{Engine, Result, Store, Config};274/// use wasmtime::component::{ResourceTable, Linker};275/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};276///277/// fn main() -> Result<()> {278/// let engine = Engine::default();279///280/// let mut linker = Linker::<MyState>::new(&engine);281/// wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;282/// // ... add any further functionality to `linker` if desired ...283///284/// let mut builder = WasiCtx::builder();285///286/// // ... configure `builder` more to add env vars, args, etc ...287///288/// let mut store = Store::new(289/// &engine,290/// MyState {291/// ctx: builder.build(),292/// table: ResourceTable::new(),293/// },294/// );295///296/// // ... use `linker` to instantiate within `store` ...297///298/// Ok(())299/// }300///301/// struct MyState {302/// ctx: WasiCtx,303/// table: ResourceTable,304/// }305///306/// impl WasiView for MyState {307/// fn ctx(&mut self) -> WasiCtxView<'_> {308/// WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }309/// }310/// }311/// ```312pub fn add_to_linker_async<T: WasiView>(linker: &mut Linker<T>) -> wasmtime::Result<()> {313let options = bindings::LinkOptions::default();314add_to_linker_with_options_async(linker, &options)315}316317/// Similar to [`add_to_linker_async`], but with the ability to enable unstable features.318pub fn add_to_linker_with_options_async<T: WasiView>(319linker: &mut Linker<T>,320options: &bindings::LinkOptions,321) -> wasmtime::Result<()> {322add_async_io_to_linker(linker)?;323add_nonblocking_to_linker(linker, options)?;324325let l = linker;326bindings::filesystem::types::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;327bindings::sockets::tcp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;328bindings::sockets::udp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;329Ok(())330}331332/// Shared functionality for [`add_to_linker_async`] and [`add_to_linker_sync`].333fn add_nonblocking_to_linker<'a, T: WasiView, O>(334linker: &mut Linker<T>,335options: &'a O,336) -> wasmtime::Result<()>337where338bindings::sockets::network::LinkOptions: From<&'a O>,339bindings::cli::exit::LinkOptions: From<&'a O>,340{341use crate::p2::bindings::{cli, clocks, filesystem, random, sockets};342343let l = linker;344clocks::wall_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;345clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;346filesystem::preopens::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;347random::random::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;348random::insecure::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;349random::insecure_seed::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;350cli::exit::add_to_linker::<T, WasiCli>(l, &options.into(), T::cli)?;351cli::environment::add_to_linker::<T, WasiCli>(l, T::cli)?;352cli::stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;353cli::stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;354cli::stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;355cli::terminal_input::add_to_linker::<T, WasiCli>(l, T::cli)?;356cli::terminal_output::add_to_linker::<T, WasiCli>(l, T::cli)?;357cli::terminal_stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;358cli::terminal_stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;359cli::terminal_stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;360sockets::tcp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;361sockets::udp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;362sockets::instance_network::add_to_linker::<T, WasiSockets>(l, T::sockets)?;363sockets::network::add_to_linker::<T, WasiSockets>(l, &options.into(), T::sockets)?;364sockets::ip_name_lookup::add_to_linker::<T, WasiSockets>(l, T::sockets)?;365Ok(())366}367368/// Same as [`add_to_linker_async`] except that this only adds interfaces369/// present in the `wasi:http/proxy` world.370pub fn add_to_linker_proxy_interfaces_async<T: WasiView>(371linker: &mut Linker<T>,372) -> wasmtime::Result<()> {373add_async_io_to_linker(linker)?;374add_proxy_interfaces_nonblocking(linker)375}376377/// Same as [`add_to_linker_sync`] except that this only adds interfaces378/// present in the `wasi:http/proxy` world.379#[doc(hidden)]380pub fn add_to_linker_proxy_interfaces_sync<T: WasiView>(381linker: &mut Linker<T>,382) -> wasmtime::Result<()> {383add_sync_wasi_io(linker)?;384add_proxy_interfaces_nonblocking(linker)385}386387fn add_proxy_interfaces_nonblocking<T: WasiView>(linker: &mut Linker<T>) -> wasmtime::Result<()> {388use crate::p2::bindings::{cli, clocks, random};389390let l = linker;391clocks::wall_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;392clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;393random::random::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;394cli::stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;395cli::stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;396cli::stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;397Ok(())398}399400/// Add all WASI interfaces from this crate into the `linker` provided.401///402/// This function will add the synchronous variant of all interfaces into the403/// [`Linker`] provided. For embeddings with async support enabled see404/// [`add_to_linker_async`] instead.405///406/// This function will add all interfaces implemented by this crate to the407/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by408/// this crate.409///410/// # Example411///412/// ```413/// use wasmtime::{Engine, Result, Store, Config};414/// use wasmtime::component::{ResourceTable, Linker};415/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};416///417/// fn main() -> Result<()> {418/// let engine = Engine::default();419///420/// let mut linker = Linker::<MyState>::new(&engine);421/// wasmtime_wasi::p2::add_to_linker_sync(&mut linker)?;422/// // ... add any further functionality to `linker` if desired ...423///424/// let mut builder = WasiCtx::builder();425///426/// // ... configure `builder` more to add env vars, args, etc ...427///428/// let mut store = Store::new(429/// &engine,430/// MyState {431/// ctx: builder.build(),432/// table: ResourceTable::new(),433/// },434/// );435///436/// // ... use `linker` to instantiate within `store` ...437///438/// Ok(())439/// }440///441/// struct MyState {442/// ctx: WasiCtx,443/// table: ResourceTable,444/// }445/// impl WasiView for MyState {446/// fn ctx(&mut self) -> WasiCtxView<'_> {447/// WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }448/// }449/// }450/// ```451pub fn add_to_linker_sync<T: WasiView>(452linker: &mut wasmtime::component::Linker<T>,453) -> wasmtime::Result<()> {454let options = bindings::sync::LinkOptions::default();455add_to_linker_with_options_sync(linker, &options)456}457458/// Similar to [`add_to_linker_sync`], but with the ability to enable unstable features.459pub fn add_to_linker_with_options_sync<T: WasiView>(460linker: &mut wasmtime::component::Linker<T>,461options: &bindings::sync::LinkOptions,462) -> wasmtime::Result<()> {463add_nonblocking_to_linker(linker, options)?;464add_sync_wasi_io(linker)?;465466let l = linker;467bindings::sync::filesystem::types::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;468bindings::sync::sockets::tcp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;469bindings::sync::sockets::udp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;470Ok(())471}472473/// Shared functionality of [`add_to_linker_sync`]` and474/// [`add_to_linker_proxy_interfaces_sync`].475fn add_sync_wasi_io<T: WasiView>(476linker: &mut wasmtime::component::Linker<T>,477) -> wasmtime::Result<()> {478let l = linker;479wasmtime_wasi_io::bindings::wasi::io::error::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;480bindings::sync::io::poll::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;481bindings::sync::io::streams::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;482Ok(())483}484485struct HasIo;486487impl HasData for HasIo {488type Data<'a> = &'a mut ResourceTable;489}490491// FIXME: it's a bit unfortunate that this can't use492// `wasmtime_wasi_io::add_to_linker` and that's because `T: WasiView`, here,493// not `T: IoView`. Ideally we'd have `impl<T: WasiView> IoView for T` but494// that's not possible with these two traits in separate crates. For now this495// is some small duplication but if this gets worse over time then we'll want496// to massage this.497fn add_async_io_to_linker<T: WasiView>(l: &mut Linker<T>) -> wasmtime::Result<()> {498wasmtime_wasi_io::bindings::wasi::io::error::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;499wasmtime_wasi_io::bindings::wasi::io::poll::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;500wasmtime_wasi_io::bindings::wasi::io::streams::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;501Ok(())502}503504505