//! # 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//! As of WASI0.2, WASI functions are not blocking from WebAssembly's point of116//! view: a WebAssembly call into these functions returns when they are117//! complete.118//!119//! This module provides an implementation of those functions in the host,120//! where for some functions, it is appropriate to implement them using121//! async Rust and the Tokio executor, so that the host implementation can be122//! nonblocking when Wasmtime's [`Config::async_support`][async] is set.123//! Synchronous wrappers are provided for all async implementations, which124//! creates a private Tokio executor.125//!126//! Users can choose between these modes of implementation using variants127//! of the add_to_linker functions:128//!129//! * For non-async users (the default of `Config`), use [`add_to_linker_sync`].130//! * For async users, use [`add_to_linker_async`].131//!132//! Note that bindings are generated once for async and once for sync. Most133//! interfaces do not change, however, so only interfaces with blocking134//! functions have bindings generated twice. Bindings are organized as:135//!136//! * [`bindings`] - default location of all bindings, blocking functions are137//! `async`138//! * [`bindings::sync`] - blocking interfaces have synchronous versions here.139//!140//! # Module-specific traits141//!142//! This module's default implementation of WASI bindings to native primitives143//! for the platform that it is compiled for. For example opening a TCP socket144//! uses the native platform to open a TCP socket (so long as [`WasiCtxBuilder`]145//! allows it). There are a few important traits, however, that are specific to146//! this module.147//!148//! * [`InputStream`] and [`OutputStream`] - these are the host traits149//! behind the WASI `input-stream` and `output-stream` types in the150//! `wasi:io/streams` interface. These enable embedders to build their own151//! custom stream and insert them into a [`ResourceTable`] (as a boxed trait152//! object, see [`DynInputStream`] and [`DynOutputStream`]) to be used from153//! wasm.154//!155//! * [`Pollable`] - this trait enables building arbitrary logic to get hooked156//! into a `pollable` resource from `wasi:io/poll`. A pollable resource is157//! created through the [`subscribe`] function.158//!159//! * [`HostWallClock`](crate::HostWallClock) and [`HostMonotonicClock`](crate::HostMonotonicClock) are used in conjunction with160//! [`WasiCtxBuilder::wall_clock`] and [`WasiCtxBuilder::monotonic_clock`] if161//! the defaults host's clock should not be used.162//!163//! * [`StdinStream`] and [`StdoutStream`] are used to provide custom164//! stdin/stdout streams if they're not inherited (or null, which is the165//! default).166//!167//! These traits enable embedders to customize small portions of WASI interfaces168//! provided while still providing all other interfaces.169//!170//! # Examples171//!172//! Usage of this module is done through a few steps to get everything hooked up:173//!174//! 1. First implement [`WasiView`] for your type which is the175//! `T` in `Store<T>`.176//! 2. Add WASI interfaces to a `wasmtime::component::Linker<T>`. This is either177//! done through top-level functions like [`add_to_linker_sync`] or through178//! individual `add_to_linker` functions in generated bindings throughout179//! this module.180//! 3. Create a [`WasiCtx`] for each `Store<T>` through [`WasiCtxBuilder`]. Each181//! WASI context is "null" or "empty" by default, so items must be explicitly182//! added to get accessed by wasm (such as env vars or program arguments).183//! 4. Use the previous `Linker<T>` to instantiate a `Component` within a184//! `Store<T>`.185//!186//! For examples see each of [`WasiView`], [`WasiCtx`], [`WasiCtxBuilder`],187//! [`add_to_linker_sync`], and [`bindings::Command`].188//!189//! [`wasmtime::component::bindgen!`]: https://docs.rs/wasmtime/latest/wasmtime/component/macro.bindgen.html190//! [`tokio`]: https://crates.io/crates/tokio191//! [`cap-std`]: https://crates.io/crates/cap-std192//! [`wasmtime-wasi-io`]: https://crates.io/crates/wasmtime-wasi-io193//! [`wasi:cli/environment`]: bindings::cli::environment::Host194//! [`wasi:cli/exit`]: bindings::cli::exit::Host195//! [`wasi:cli/stderr`]: bindings::cli::stderr::Host196//! [`wasi:cli/stdin`]: bindings::cli::stdin::Host197//! [`wasi:cli/stdout`]: bindings::cli::stdout::Host198//! [`wasi:cli/terminal-input`]: bindings::cli::terminal_input::Host199//! [`wasi:cli/terminal-output`]: bindings::cli::terminal_output::Host200//! [`wasi:cli/terminal-stdin`]: bindings::cli::terminal_stdin::Host201//! [`wasi:cli/terminal-stdout`]: bindings::cli::terminal_stdout::Host202//! [`wasi:cli/terminal-stderr`]: bindings::cli::terminal_stderr::Host203//! [`wasi:clocks/monotonic-clock`]: bindings::clocks::monotonic_clock::Host204//! [`wasi:clocks/wall-clock`]: bindings::clocks::wall_clock::Host205//! [`wasi:filesystem/preopens`]: bindings::filesystem::preopens::Host206//! [`wasi:filesystem/types`]: bindings::filesystem::types::Host207//! [`wasi:io/error`]: wasmtime_wasi_io::bindings::wasi::io::error::Host208//! [`wasi:io/poll`]: wasmtime_wasi_io::bindings::wasi::io::poll::Host209//! [`wasi:io/streams`]: wasmtime_wasi_io::bindings::wasi::io::streams::Host210//! [`wasi:random/insecure-seed`]: bindings::random::insecure_seed::Host211//! [`wasi:random/insecure`]: bindings::random::insecure::Host212//! [`wasi:random/random`]: bindings::random::random::Host213//! [`wasi:sockets/instance-network`]: bindings::sockets::instance_network::Host214//! [`wasi:sockets/ip-name-lookup`]: bindings::sockets::ip_name_lookup::Host215//! [`wasi:sockets/network`]: bindings::sockets::network::Host216//! [`wasi:sockets/tcp-create-socket`]: bindings::sockets::tcp_create_socket::Host217//! [`wasi:sockets/tcp`]: bindings::sockets::tcp::Host218//! [`wasi:sockets/udp-create-socket`]: bindings::sockets::udp_create_socket::Host219//! [`wasi:sockets/udp`]: bindings::sockets::udp::Host220//! [async]: https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.async_support221//! [`ResourceTable`]: wasmtime::component::ResourceTable222223use crate::WasiView;224use crate::cli::{WasiCli, WasiCliView as _};225use crate::clocks::{WasiClocks, WasiClocksView as _};226use crate::filesystem::{WasiFilesystem, WasiFilesystemView as _};227use crate::random::WasiRandom;228use crate::sockets::{WasiSockets, WasiSocketsView as _};229use wasmtime::component::{HasData, Linker, ResourceTable};230231pub mod bindings;232pub(crate) mod filesystem;233mod host;234mod ip_name_lookup;235mod network;236pub mod pipe;237mod poll;238mod stdio;239mod tcp;240mod udp;241mod write_stream;242243pub use self::filesystem::{FsError, FsResult, ReaddirIterator};244pub use self::network::{Network, SocketError, SocketResult};245pub use self::stdio::IsATTY;246pub(crate) use tcp::P2TcpStreamingState;247// These contents of wasmtime-wasi-io are re-exported by this module for compatibility:248// they were originally defined in this module before being factored out, and many249// users of this module depend on them at these names.250pub use wasmtime_wasi_io::poll::{DynFuture, DynPollable, MakeFuture, Pollable, subscribe};251pub use wasmtime_wasi_io::streams::{252DynInputStream, DynOutputStream, Error as IoError, InputStream, OutputStream, StreamError,253StreamResult,254};255256/// Add all WASI interfaces from this crate into the `linker` provided.257///258/// This function will add the `async` variant of all interfaces into the259/// [`Linker`] provided. By `async` this means that this function is only260/// compatible with [`Config::async_support(true)`][async]. For embeddings with261/// async support disabled see [`add_to_linker_sync`] instead.262///263/// This function will add all interfaces implemented by this crate to the264/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by265/// this crate.266///267/// [async]: wasmtime::Config::async_support268///269/// # Example270///271/// ```272/// use wasmtime::{Engine, Result, Store, Config};273/// use wasmtime::component::{ResourceTable, Linker};274/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};275///276/// fn main() -> Result<()> {277/// let mut config = Config::new();278/// config.async_support(true);279/// let engine = Engine::new(&config)?;280///281/// let mut linker = Linker::<MyState>::new(&engine);282/// wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;283/// // ... add any further functionality to `linker` if desired ...284///285/// let mut builder = WasiCtx::builder();286///287/// // ... configure `builder` more to add env vars, args, etc ...288///289/// let mut store = Store::new(290/// &engine,291/// MyState {292/// ctx: builder.build(),293/// table: ResourceTable::new(),294/// },295/// );296///297/// // ... use `linker` to instantiate within `store` ...298///299/// Ok(())300/// }301///302/// struct MyState {303/// ctx: WasiCtx,304/// table: ResourceTable,305/// }306///307/// impl WasiView for MyState {308/// fn ctx(&mut self) -> WasiCtxView<'_> {309/// WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }310/// }311/// }312/// ```313pub fn add_to_linker_async<T: WasiView>(linker: &mut Linker<T>) -> anyhow::Result<()> {314let options = bindings::LinkOptions::default();315add_to_linker_with_options_async(linker, &options)316}317318/// Similar to [`add_to_linker_async`], but with the ability to enable unstable features.319pub fn add_to_linker_with_options_async<T: WasiView>(320linker: &mut Linker<T>,321options: &bindings::LinkOptions,322) -> anyhow::Result<()> {323add_async_io_to_linker(linker)?;324add_nonblocking_to_linker(linker, options)?;325326let l = linker;327bindings::filesystem::types::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;328bindings::sockets::tcp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;329bindings::sockets::udp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;330Ok(())331}332333/// Shared functionality for [`add_to_linker_async`] and [`add_to_linker_sync`].334fn add_nonblocking_to_linker<'a, T: WasiView, O>(335linker: &mut Linker<T>,336options: &'a O,337) -> anyhow::Result<()>338where339bindings::sockets::network::LinkOptions: From<&'a O>,340bindings::cli::exit::LinkOptions: From<&'a O>,341{342use crate::p2::bindings::{cli, clocks, filesystem, random, sockets};343344let l = linker;345clocks::wall_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;346clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;347filesystem::preopens::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;348random::random::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;349random::insecure::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;350random::insecure_seed::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;351cli::exit::add_to_linker::<T, WasiCli>(l, &options.into(), T::cli)?;352cli::environment::add_to_linker::<T, WasiCli>(l, T::cli)?;353cli::stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;354cli::stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;355cli::stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;356cli::terminal_input::add_to_linker::<T, WasiCli>(l, T::cli)?;357cli::terminal_output::add_to_linker::<T, WasiCli>(l, T::cli)?;358cli::terminal_stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;359cli::terminal_stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;360cli::terminal_stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;361sockets::tcp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;362sockets::udp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;363sockets::instance_network::add_to_linker::<T, WasiSockets>(l, T::sockets)?;364sockets::network::add_to_linker::<T, WasiSockets>(l, &options.into(), T::sockets)?;365sockets::ip_name_lookup::add_to_linker::<T, WasiSockets>(l, T::sockets)?;366Ok(())367}368369/// Same as [`add_to_linker_async`] except that this only adds interfaces370/// present in the `wasi:http/proxy` world.371pub fn add_to_linker_proxy_interfaces_async<T: WasiView>(372linker: &mut Linker<T>,373) -> anyhow::Result<()> {374add_async_io_to_linker(linker)?;375add_proxy_interfaces_nonblocking(linker)376}377378/// Same as [`add_to_linker_sync`] except that this only adds interfaces379/// present in the `wasi:http/proxy` world.380#[doc(hidden)]381pub fn add_to_linker_proxy_interfaces_sync<T: WasiView>(382linker: &mut Linker<T>,383) -> anyhow::Result<()> {384add_sync_wasi_io(linker)?;385add_proxy_interfaces_nonblocking(linker)386}387388fn add_proxy_interfaces_nonblocking<T: WasiView>(linker: &mut Linker<T>) -> anyhow::Result<()> {389use crate::p2::bindings::{cli, clocks, random};390391let l = linker;392clocks::wall_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;393clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;394random::random::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;395cli::stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;396cli::stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;397cli::stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;398Ok(())399}400401/// Add all WASI interfaces from this crate into the `linker` provided.402///403/// This function will add the synchronous variant of all interfaces into the404/// [`Linker`] provided. By synchronous this means that this function is only405/// compatible with [`Config::async_support(false)`][async]. For embeddings406/// with async support enabled see [`add_to_linker_async`] instead.407///408/// This function will add all interfaces implemented by this crate to the409/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by410/// this crate.411///412/// [async]: wasmtime::Config::async_support413///414/// # Example415///416/// ```417/// use wasmtime::{Engine, Result, Store, Config};418/// use wasmtime::component::{ResourceTable, Linker};419/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};420///421/// fn main() -> Result<()> {422/// let engine = Engine::default();423///424/// let mut linker = Linker::<MyState>::new(&engine);425/// wasmtime_wasi::p2::add_to_linker_sync(&mut linker)?;426/// // ... add any further functionality to `linker` if desired ...427///428/// let mut builder = WasiCtx::builder();429///430/// // ... configure `builder` more to add env vars, args, etc ...431///432/// let mut store = Store::new(433/// &engine,434/// MyState {435/// ctx: builder.build(),436/// table: ResourceTable::new(),437/// },438/// );439///440/// // ... use `linker` to instantiate within `store` ...441///442/// Ok(())443/// }444///445/// struct MyState {446/// ctx: WasiCtx,447/// table: ResourceTable,448/// }449/// impl WasiView for MyState {450/// fn ctx(&mut self) -> WasiCtxView<'_> {451/// WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }452/// }453/// }454/// ```455pub fn add_to_linker_sync<T: WasiView>(456linker: &mut wasmtime::component::Linker<T>,457) -> anyhow::Result<()> {458let options = bindings::sync::LinkOptions::default();459add_to_linker_with_options_sync(linker, &options)460}461462/// Similar to [`add_to_linker_sync`], but with the ability to enable unstable features.463pub fn add_to_linker_with_options_sync<T: WasiView>(464linker: &mut wasmtime::component::Linker<T>,465options: &bindings::sync::LinkOptions,466) -> anyhow::Result<()> {467add_nonblocking_to_linker(linker, options)?;468add_sync_wasi_io(linker)?;469470let l = linker;471bindings::sync::filesystem::types::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;472bindings::sync::sockets::tcp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;473bindings::sync::sockets::udp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;474Ok(())475}476477/// Shared functionality of [`add_to_linker_sync`]` and478/// [`add_to_linker_proxy_interfaces_sync`].479fn add_sync_wasi_io<T: WasiView>(480linker: &mut wasmtime::component::Linker<T>,481) -> anyhow::Result<()> {482let l = linker;483wasmtime_wasi_io::bindings::wasi::io::error::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;484bindings::sync::io::poll::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;485bindings::sync::io::streams::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;486Ok(())487}488489struct HasIo;490491impl HasData for HasIo {492type Data<'a> = &'a mut ResourceTable;493}494495// FIXME: it's a bit unfortunate that this can't use496// `wasmtime_wasi_io::add_to_linker` and that's because `T: WasiView`, here,497// not `T: IoView`. Ideally we'd have `impl<T: WasiView> IoView for T` but498// that's not possible with these two traits in separate crates. For now this499// is some small duplication but if this gets worse over time then we'll want500// to massage this.501fn add_async_io_to_linker<T: WasiView>(l: &mut Linker<T>) -> anyhow::Result<()> {502wasmtime_wasi_io::bindings::wasi::io::error::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;503wasmtime_wasi_io::bindings::wasi::io::poll::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;504wasmtime_wasi_io::bindings::wasi::io::streams::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;505Ok(())506}507508509