Skip to main content

wasmtime_wasi/p2/
mod.rs

1//! # Wasmtime's WASIp2 Implementation
2//!
3//!
4//! This module provides a Wasmtime host implementation of WASI 0.2 (aka WASIp2
5//! aka Preview 2) and WASI 0.1 (aka WASIp1 aka Preview 1). WASI is implemented
6//! with the Rust crates [`tokio`] and [`cap-primitives`] primarily, meaning that
7//! operations are implemented in terms of their native platform equivalents by
8//! default.
9//!
10//! # WASIp2 interfaces
11//!
12//! This module contains implementations of the following interfaces:
13//!
14//! * [`wasi:cli/environment`]
15//! * [`wasi:cli/exit`]
16//! * [`wasi:cli/stderr`]
17//! * [`wasi:cli/stdin`]
18//! * [`wasi:cli/stdout`]
19//! * [`wasi:cli/terminal-input`]
20//! * [`wasi:cli/terminal-output`]
21//! * [`wasi:cli/terminal-stderr`]
22//! * [`wasi:cli/terminal-stdin`]
23//! * [`wasi:cli/terminal-stdout`]
24//! * [`wasi:clocks/monotonic-clock`]
25//! * [`wasi:clocks/wall-clock`]
26//! * [`wasi:filesystem/preopens`]
27//! * [`wasi:filesystem/types`]
28//! * [`wasi:random/insecure-seed`]
29//! * [`wasi:random/insecure`]
30//! * [`wasi:random/random`]
31//! * [`wasi:sockets/instance-network`]
32//! * [`wasi:sockets/ip-name-lookup`]
33//! * [`wasi:sockets/network`]
34//! * [`wasi:sockets/tcp-create-socket`]
35//! * [`wasi:sockets/tcp`]
36//! * [`wasi:sockets/udp-create-socket`]
37//! * [`wasi:sockets/udp`]
38//!
39//! Most traits are implemented for [`WasiCtxView`] trait which provides
40//! access to [`WasiCtx`] and [`ResourceTable`], which defines the configuration
41//! for WASI and handle state. The [`WasiView`] trait is used to acquire and
42//! construct a [`WasiCtxView`].
43//!
44//! The [`wasmtime-wasi-io`] crate contains implementations of the
45//! following interfaces, and this module reuses those implementations:
46//!
47//! * [`wasi:io/error`]
48//! * [`wasi:io/poll`]
49//! * [`wasi:io/streams`]
50//!
51//! These traits are implemented directly for [`ResourceTable`]. All aspects of
52//! `wasmtime-wasi-io` that are used by this module are re-exported. Unless you
53//! are implementing other host functionality that needs to interact with the
54//! WASI scheduler and don't want to use other functionality provided by
55//! `wasmtime-wasi`, you don't need to take a direct dependency on
56//! `wasmtime-wasi-io`.
57//!
58//! # Generated Bindings
59//!
60//! This module uses [`wasmtime::component::bindgen!`] to generate bindings for
61//! all WASI interfaces. Raw bindings are available in the [`bindings`] submodule
62//! of this module. Downstream users can either implement these traits themselves
63//! or you can use the built-in implementations in this module for
64//! `WasiImpl<T: WasiView>`.
65//!
66//! # The `WasiView` trait
67//!
68//! This module's implementation of WASI is done in terms of an implementation of
69//! [`WasiView`]. This trait provides a "view" into WASI-related state that is
70//! contained within a [`Store<T>`](wasmtime::Store).
71//!
72//! For all of the generated bindings in this module (Host traits),
73//! implementations are provided looking like:
74//!
75//! ```
76//! # use wasmtime_wasi::WasiCtxView;
77//! # trait WasiView {}
78//! # mod bindings { pub mod wasi { pub trait Host {} } }
79//! impl bindings::wasi::Host for WasiCtxView<'_> {
80//!     // ...
81//! }
82//! ```
83//!
84//! where the [`WasiCtxView`] type comes from [`WasiView::ctx`] for the type
85//! contained within the `Store<T>`. The [`add_to_linker_sync`] and
86//! [`add_to_linker_async`] function then require that `T: WasiView` with
87//! [`Linker<T>`](wasmtime::component::Linker).
88//!
89//! To implement the [`WasiView`] trait you will first select a
90//! `T` to put in `Store<T>` (typically, by defining your own struct).
91//! Somewhere within `T` you'll store:
92//!
93//! * [`ResourceTable`] - created through default constructors.
94//! * [`WasiCtx`] - created through [`WasiCtxBuilder`].
95//!
96//! You'll then write an implementation of the [`WasiView`]
97//! trait to access those items in your `T`. For example:
98//! ```
99//! use wasmtime::component::ResourceTable;
100//! use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
101//!
102//! struct MyCtx {
103//!     table: ResourceTable,
104//!     wasi: WasiCtx,
105//! }
106//!
107//! impl WasiView for MyCtx {
108//!     fn ctx(&mut self) -> WasiCtxView<'_> {
109//!         WasiCtxView { ctx: &mut self.wasi, table: &mut self.table }
110//!     }
111//! }
112//! ```
113//!
114//! # Async and Sync
115//!
116//! All WASIp2 functions are blocking from WebAssembly's point of view: a
117//! WebAssembly call into these functions returns only when they are complete.
118//!
119//! This module provides an implementation of those functions in the host, where
120//! for some functions, it is appropriate to implement them using async Rust and
121//! the Tokio executor. The host implementation still blocks WebAssembly, but it
122//! does not block the host's thread. Synchronous wrappers are also provided for
123//! all async implementations, which create a private Tokio executor.
124//!
125//! Users can choose between these modes of implementation using variants
126//! of the add_to_linker functions:
127//!
128//! * For non-async users, use [`add_to_linker_sync`].
129//! * For async users, use [`add_to_linker_async`].
130//!
131//! Note that bindings are generated once for async and once for sync. Most
132//! interfaces do not change, however, so only interfaces with blocking
133//! functions have bindings generated twice. Bindings are organized as:
134//!
135//! * [`bindings`] - default location of all bindings, blocking functions are
136//!   `async`
137//! * [`bindings::sync`] - blocking interfaces have synchronous versions here.
138//!
139//! # Module-specific traits
140//!
141//! This module's default implementation of WASI bindings to native primitives
142//! for the platform that it is compiled for. For example opening a TCP socket
143//! uses the native platform to open a TCP socket (so long as [`WasiCtxBuilder`]
144//! allows it). There are a few important traits, however, that are specific to
145//! this module.
146//!
147//! * [`InputStream`] and [`OutputStream`] - these are the host traits
148//!   behind the WASI `input-stream` and `output-stream` types in the
149//!   `wasi:io/streams` interface. These enable embedders to build their own
150//!   custom stream and insert them into a [`ResourceTable`] (as a boxed trait
151//!   object, see [`DynInputStream`] and [`DynOutputStream`]) to be used from
152//!   wasm.
153//!
154//! * [`Pollable`] - this trait enables building arbitrary logic to get hooked
155//!   into a `pollable` resource from `wasi:io/poll`. A pollable resource is
156//!   created through the [`subscribe`] function.
157//!
158//! * [`HostWallClock`](crate::HostWallClock) and [`HostMonotonicClock`](crate::HostMonotonicClock) are used in conjunction with
159//!   [`WasiCtxBuilder::wall_clock`] and [`WasiCtxBuilder::monotonic_clock`] if
160//!   the defaults host's clock should not be used.
161//!
162//! * [`StdinStream`] and [`StdoutStream`] are used to provide custom
163//!   stdin/stdout streams if they're not inherited (or null, which is the
164//!   default).
165//!
166//! These traits enable embedders to customize small portions of WASI interfaces
167//! provided while still providing all other interfaces.
168//!
169//! # Examples
170//!
171//! Usage of this module is done through a few steps to get everything hooked up:
172//!
173//! 1. First implement [`WasiView`] for your type which is the
174//!    `T` in `Store<T>`.
175//! 2. Add WASI interfaces to a `wasmtime::component::Linker<T>`. This is either
176//!    done through top-level functions like [`add_to_linker_sync`] or through
177//!    individual `add_to_linker` functions in generated bindings throughout
178//!    this module.
179//! 3. Create a [`WasiCtx`] for each `Store<T>` through [`WasiCtxBuilder`]. Each
180//!    WASI context is "null" or "empty" by default, so items must be explicitly
181//!    added to get accessed by wasm (such as env vars or program arguments).
182//! 4. Use the previous `Linker<T>` to instantiate a `Component` within a
183//!    `Store<T>`.
184//!
185//! For examples see each of [`WasiView`], [`WasiCtx`], [`WasiCtxBuilder`],
186//! [`add_to_linker_sync`], and [`bindings::Command`].
187//!
188//! [`wasmtime::component::bindgen!`]: https://docs.rs/wasmtime/latest/wasmtime/component/macro.bindgen.html
189//! [`tokio`]: https://crates.io/crates/tokio
190//! [`cap-primitives`]: https://crates.io/crates/cap-primitives
191//! [`wasmtime-wasi-io`]: https://crates.io/crates/wasmtime-wasi-io
192//! [`wasi:cli/environment`]: bindings::cli::environment::Host
193//! [`wasi:cli/exit`]: bindings::cli::exit::Host
194//! [`wasi:cli/stderr`]: bindings::cli::stderr::Host
195//! [`wasi:cli/stdin`]: bindings::cli::stdin::Host
196//! [`wasi:cli/stdout`]: bindings::cli::stdout::Host
197//! [`wasi:cli/terminal-input`]: bindings::cli::terminal_input::Host
198//! [`wasi:cli/terminal-output`]: bindings::cli::terminal_output::Host
199//! [`wasi:cli/terminal-stdin`]: bindings::cli::terminal_stdin::Host
200//! [`wasi:cli/terminal-stdout`]: bindings::cli::terminal_stdout::Host
201//! [`wasi:cli/terminal-stderr`]: bindings::cli::terminal_stderr::Host
202//! [`wasi:clocks/monotonic-clock`]: bindings::clocks::monotonic_clock::Host
203//! [`wasi:clocks/wall-clock`]: bindings::clocks::wall_clock::Host
204//! [`wasi:filesystem/preopens`]: bindings::filesystem::preopens::Host
205//! [`wasi:filesystem/types`]: bindings::filesystem::types::Host
206//! [`wasi:io/error`]: wasmtime_wasi_io::bindings::wasi::io::error::Host
207//! [`wasi:io/poll`]: wasmtime_wasi_io::bindings::wasi::io::poll::Host
208//! [`wasi:io/streams`]: wasmtime_wasi_io::bindings::wasi::io::streams::Host
209//! [`wasi:random/insecure-seed`]: bindings::random::insecure_seed::Host
210//! [`wasi:random/insecure`]: bindings::random::insecure::Host
211//! [`wasi:random/random`]: bindings::random::random::Host
212//! [`wasi:sockets/instance-network`]: bindings::sockets::instance_network::Host
213//! [`wasi:sockets/ip-name-lookup`]: bindings::sockets::ip_name_lookup::Host
214//! [`wasi:sockets/network`]: bindings::sockets::network::Host
215//! [`wasi:sockets/tcp-create-socket`]: bindings::sockets::tcp_create_socket::Host
216//! [`wasi:sockets/tcp`]: bindings::sockets::tcp::Host
217//! [`wasi:sockets/udp-create-socket`]: bindings::sockets::udp_create_socket::Host
218//! [`wasi:sockets/udp`]: bindings::sockets::udp::Host
219//! [`ResourceTable`]: wasmtime::component::ResourceTable
220//! [`WasiCtx`]: crate::WasiCtx
221//! [`WasiCtxView`]: crate::WasiCtxView
222//! [`WasiCtxBuilder`]: crate::WasiCtxBuilder
223//! [`WasiCtxBuilder::wall_clock`]: crate::WasiCtxBuilder::wall_clock
224//! [`WasiCtxBuilder::monotonic_clock`]: crate::WasiCtxBuilder::monotonic_clock
225//! [`StdinStream`]: crate::cli::StdinStream
226//! [`StdoutStream`]: crate::cli::StdoutStream
227
228use crate::cli::{WasiCli, WasiCliNamed, WasiCliView as _};
229use crate::clocks::{WasiClocks, WasiClocksNamed, WasiClocksView as _};
230use crate::filesystem::{WasiFilesystem, WasiFilesystemNamed, WasiFilesystemView as _};
231use crate::random::{WasiRandom, WasiRandomNamed};
232use crate::sockets::{WasiSockets, WasiSocketsNamed, WasiSocketsView as _};
233use crate::{NamedId, WasiCtxNamedView, WasiNamedView, WasiView};
234use wasmtime::component::{Component, HasData, Linker, ResourceTable};
235
236pub mod bindings;
237pub(crate) mod filesystem;
238mod host;
239mod ip_name_lookup;
240mod network;
241pub mod pipe;
242mod poll;
243mod stdio;
244mod tcp;
245mod udp;
246mod write_stream;
247
248pub use self::filesystem::{FsError, FsResult, ReaddirIterator};
249pub use self::network::{Network, SocketError, SocketResult};
250pub use self::stdio::IsATTY;
251pub use tcp::TcpSocket;
252pub use udp::UdpSocket;
253// These contents of wasmtime-wasi-io are re-exported by this module for compatibility:
254// they were originally defined in this module before being factored out, and many
255// users of this module depend on them at these names.
256pub use wasmtime_wasi_io::poll::{DynFuture, DynPollable, MakeFuture, Pollable, subscribe};
257pub use wasmtime_wasi_io::streams::{
258    DynInputStream, DynOutputStream, Error as IoError, InputStream, OutputStream, StreamError,
259    StreamResult,
260};
261
262/// Add all WASI interfaces from this crate into the `linker` provided.
263///
264/// This function will add the `async` variant of all interfaces into the
265/// [`Linker`] provided. For embeddings with async support disabled see
266/// [`add_to_linker_sync`] instead.
267///
268/// This function will add all interfaces implemented by this crate to the
269/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by
270/// this crate.
271///
272/// # Example
273///
274/// ```
275/// use wasmtime::{Engine, Result, Store, Config};
276/// use wasmtime::component::{ResourceTable, Linker};
277/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
278///
279/// fn main() -> Result<()> {
280///     let engine = Engine::default();
281///
282///     let mut linker = Linker::<MyState>::new(&engine);
283///     wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
284///     // ... add any further functionality to `linker` if desired ...
285///
286///     let mut builder = WasiCtx::builder();
287///
288///     // ... configure `builder` more to add env vars, args, etc ...
289///
290///     let mut store = Store::new(
291///         &engine,
292///         MyState {
293///             ctx: builder.build(),
294///             table: ResourceTable::new(),
295///         },
296///     );
297///
298///     // ... use `linker` to instantiate within `store` ...
299///
300///     Ok(())
301/// }
302///
303/// struct MyState {
304///     ctx: WasiCtx,
305///     table: ResourceTable,
306/// }
307///
308/// impl WasiView for MyState {
309///     fn ctx(&mut self) -> WasiCtxView<'_> {
310///         WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }
311///     }
312/// }
313/// ```
314pub fn add_to_linker_async<T: WasiView>(linker: &mut Linker<T>) -> wasmtime::Result<()> {
315    let options = bindings::LinkOptions::default();
316    add_to_linker_with_options_async(linker, &options)
317}
318
319/// Similar to [`add_to_linker_async`], but with the ability to enable unstable features.
320pub fn add_to_linker_with_options_async<T: WasiView>(
321    linker: &mut Linker<T>,
322    options: &bindings::LinkOptions,
323) -> wasmtime::Result<()> {
324    add_async_io_to_linker(linker)?;
325    add_nonblocking_to_linker(linker, options)?;
326
327    let l = linker;
328    bindings::filesystem::types::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;
329    bindings::sockets::tcp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
330    bindings::sockets::udp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
331    bindings::sockets::udp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
332    bindings::sockets::ip_name_lookup::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
333    Ok(())
334}
335
336/// Shared functionality for [`add_to_linker_async`] and [`add_to_linker_sync`].
337fn add_nonblocking_to_linker<'a, T: WasiView, O>(
338    linker: &mut Linker<T>,
339    options: &'a O,
340) -> wasmtime::Result<()>
341where
342    bindings::sockets::network::LinkOptions: From<&'a O>,
343{
344    use crate::p2::bindings::{cli, clocks, filesystem, random, sockets};
345
346    let l = linker;
347    clocks::wall_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;
348    clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;
349    filesystem::preopens::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;
350    random::random::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;
351    random::insecure::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;
352    random::insecure_seed::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;
353    cli::exit::add_to_linker::<T, WasiCli>(l, T::cli)?;
354    cli::environment::add_to_linker::<T, WasiCli>(l, T::cli)?;
355    cli::stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;
356    cli::stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;
357    cli::stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;
358    cli::terminal_input::add_to_linker::<T, WasiCli>(l, T::cli)?;
359    cli::terminal_output::add_to_linker::<T, WasiCli>(l, T::cli)?;
360    cli::terminal_stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;
361    cli::terminal_stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;
362    cli::terminal_stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;
363    sockets::tcp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
364    sockets::instance_network::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
365    sockets::network::add_to_linker::<T, WasiSockets>(l, &options.into(), T::sockets)?;
366    Ok(())
367}
368
369/// Same as [`add_to_linker_async`] except that this only adds interfaces
370/// present in the `wasi:http/proxy` world.
371pub fn add_to_linker_proxy_interfaces_async<T: WasiView>(
372    linker: &mut Linker<T>,
373) -> wasmtime::Result<()> {
374    add_async_io_to_linker(linker)?;
375    add_proxy_interfaces_nonblocking(linker)
376}
377
378/// Same as [`add_to_linker_sync`] except that this only adds interfaces
379/// present in the `wasi:http/proxy` world.
380#[doc(hidden)]
381pub fn add_to_linker_proxy_interfaces_sync<T: WasiView>(
382    linker: &mut Linker<T>,
383) -> wasmtime::Result<()> {
384    add_sync_wasi_io(linker)?;
385    add_proxy_interfaces_nonblocking(linker)
386}
387
388fn add_proxy_interfaces_nonblocking<T: WasiView>(linker: &mut Linker<T>) -> wasmtime::Result<()> {
389    use crate::p2::bindings::{cli, clocks, random};
390
391    let l = linker;
392    clocks::wall_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;
393    clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;
394    random::random::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;
395    cli::stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;
396    cli::stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;
397    cli::stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;
398    Ok(())
399}
400
401/// Add all WASI interfaces from this crate into the `linker` provided.
402///
403/// This function will add the synchronous variant of all interfaces into the
404/// [`Linker`] provided. For embeddings with async support enabled see
405/// [`add_to_linker_async`] instead.
406///
407/// This function will add all interfaces implemented by this crate to the
408/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by
409/// this crate.
410///
411/// # Example
412///
413/// ```
414/// use wasmtime::{Engine, Result, Store, Config};
415/// use wasmtime::component::{ResourceTable, Linker};
416/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
417///
418/// fn main() -> Result<()> {
419///     let engine = Engine::default();
420///
421///     let mut linker = Linker::<MyState>::new(&engine);
422///     wasmtime_wasi::p2::add_to_linker_sync(&mut linker)?;
423///     // ... add any further functionality to `linker` if desired ...
424///
425///     let mut builder = WasiCtx::builder();
426///
427///     // ... configure `builder` more to add env vars, args, etc ...
428///
429///     let mut store = Store::new(
430///         &engine,
431///         MyState {
432///             ctx: builder.build(),
433///             table: ResourceTable::new(),
434///         },
435///     );
436///
437///     // ... use `linker` to instantiate within `store` ...
438///
439///     Ok(())
440/// }
441///
442/// struct MyState {
443///     ctx: WasiCtx,
444///     table: ResourceTable,
445/// }
446/// impl WasiView for MyState {
447///     fn ctx(&mut self) -> WasiCtxView<'_> {
448///         WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }
449///     }
450/// }
451/// ```
452pub fn add_to_linker_sync<T: WasiView>(
453    linker: &mut wasmtime::component::Linker<T>,
454) -> wasmtime::Result<()> {
455    let options = bindings::sync::LinkOptions::default();
456    add_to_linker_with_options_sync(linker, &options)
457}
458
459/// Similar to [`add_to_linker_sync`], but with the ability to enable unstable features.
460pub fn add_to_linker_with_options_sync<T: WasiView>(
461    linker: &mut wasmtime::component::Linker<T>,
462    options: &bindings::sync::LinkOptions,
463) -> wasmtime::Result<()> {
464    add_nonblocking_to_linker(linker, options)?;
465    add_sync_wasi_io(linker)?;
466
467    let l = linker;
468    bindings::sync::filesystem::types::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;
469    bindings::sync::sockets::tcp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
470    bindings::sync::sockets::udp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
471    bindings::sync::sockets::udp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
472    bindings::sync::sockets::ip_name_lookup::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
473    Ok(())
474}
475
476/// Shared functionality of [`add_to_linker_sync`]` and
477/// [`add_to_linker_proxy_interfaces_sync`].
478fn add_sync_wasi_io<T: WasiView>(
479    linker: &mut wasmtime::component::Linker<T>,
480) -> wasmtime::Result<()> {
481    let l = linker;
482    wasmtime_wasi_io::bindings::wasi::io::error::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
483    bindings::sync::io::poll::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
484    bindings::sync::io::streams::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
485    Ok(())
486}
487
488struct HasIo;
489
490impl HasData for HasIo {
491    type Data<'a> = &'a mut ResourceTable;
492}
493
494// FIXME: it's a bit unfortunate that this can't use
495// `wasmtime_wasi_io::add_to_linker` and that's because `T: WasiView`, here,
496// not `T: IoView`. Ideally we'd have `impl<T: WasiView> IoView for T` but
497// that's not possible with these two traits in separate crates. For now this
498// is some small duplication but if this gets worse over time then we'll want
499// to massage this.
500fn add_async_io_to_linker<T: WasiView>(l: &mut Linker<T>) -> wasmtime::Result<()> {
501    wasmtime_wasi_io::bindings::wasi::io::error::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
502    wasmtime_wasi_io::bindings::wasi::io::poll::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
503    wasmtime_wasi_io::bindings::wasi::io::streams::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
504    Ok(())
505}
506
507/// Interfaces that are added via [`add_named_to_linker_async`].
508#[derive(Copy, Clone, PartialEq, Eq, Debug)]
509pub enum Interface {
510    /// `wasi:clocks/monotonic-clock`
511    ClocksMonotonicClock,
512    /// `wasi:clocks/wall-clock`
513    ClocksWallClock,
514    /// `wasi:random/random`
515    RandomRandom,
516    /// `wasi:random/insecure`
517    RandomInsecure,
518    /// `wasi:random/insecure-seed`
519    RandomInsecureSeed,
520    /// `wasi:cli/exit`
521    CliExit,
522    /// `wasi:cli/environment`
523    CliEnvironment,
524    /// `wasi:cli/stdin`
525    CliStdin,
526    /// `wasi:cli/stdout`
527    CliStdout,
528    /// `wasi:cli/stderr`
529    CliStderr,
530    /// `wasi:cli/terminal-input`
531    CliTerminalInput,
532    /// `wasi:cli/terminal-output`
533    CliTerminalOutput,
534    /// `wasi:cli/terminal-stdin`
535    CliTerminalStdin,
536    /// `wasi:cli/terminal-stdout`
537    CliTerminalStdout,
538    /// `wasi:cli/terminal-stderr`
539    CliTerminalStderr,
540    /// `wasi:filesystem/types`
541    FilesystemTypes,
542    /// `wasi:filesystem/preopens`
543    FilesystemPreopens,
544    /// `wasi:sockets/instance-network`
545    SocketsInstanceNetwork,
546    /// `wasi:sockets/network`
547    SocketsNetwork,
548    /// `wasi:sockets/ip-name-lookup`
549    SocketsIpNameLookup,
550    /// `wasi:sockets/tcp-create-socket`
551    SocketsTcpCreateSocket,
552    /// `wasi:sockets/tcp`
553    SocketsTcp,
554    /// `wasi:sockets/udp-create-socket`
555    SocketsUdpCreateSocket,
556    /// `wasi:sockets/udp`
557    SocketsUdp,
558}
559
560/// Add all WASI interfaces from this crate into the `linker` provided for any
561/// named imports that a component has.
562///
563/// This function is similar to [`add_to_linker_async`] except that it's specifically
564/// designed to work with named imports of WASI interfaces that components may
565/// have. This requires a [`Component`] parameter to be passed in when
566/// populating the [`Linker`] provided to see what the [`Component`] actually
567/// imports.
568///
569/// Like [`add_to_linker_async`] this adds the `async` variant of all
570/// interfaces. If this isn't low level enough you can invoke the
571/// bindgen-generated `add_to_linker` functions within the [`named_imports`]
572/// module directly instead.
573///
574/// [`named_imports`]: crate::p2::bindings::named_imports
575///
576/// The `lookup` function provided here is invoked for every named import found
577/// for a particular interface. The [`Interface`] given is what's being bound,
578/// and the `&str` argument is the name that the component imports it as. The
579/// embedder can then decide how it would like to allocate a [`NamedId`] for
580/// this import. If `Ok` is returned then the linker is populated with this
581/// name, and imported functions will pass the [`NamedId`] later to the
582/// implementation of [`WasiNamedView`] on `T` when invoked. If `Err` is
583/// returned then the error will cause this entire function to fail and this
584/// function call will return the same error.
585///
586/// # Example
587///
588/// ```
589/// use std::collections::HashMap;
590/// use wasmtime::component::{Component, Linker, ResourceTable};
591/// use wasmtime::{Engine, Result, Store, Config};
592/// use wasmtime_wasi::{NamedId, WasiCtx, WasiCtxView, WasiNamedView};
593///
594/// fn main() -> Result<()> {
595///     let engine = Engine::default();
596///     let component = Component::new(&engine, "(component)")?;
597///
598///     let mut linker = Linker::<MyState>::new(&engine);
599///
600///     // ... add default functionality to `linker` as needed ...
601///
602///     // and then additionally fill in any specific named imports `component`
603///     // might have for WASI interfaces.
604///     let mut name_map = HashMap::new();
605///     wasmtime_wasi::p2::add_named_to_linker_async(&mut linker, &component, |_i, name| {
606///         let len = name_map.len();
607///         Ok(NamedId(*name_map.entry(name.to_string()).or_insert(len)))
608///     })?;
609///
610///     // Here a `WasiCtx` is allocated per-named-import and will then be
611///     // referred to internally by the [`NamedId`] allocated above. You could
612///     // also use `name_map` to configure each context differently.
613///     let mut my_state = MyState::default();
614///     for _ in 0..name_map.len() {
615///         my_state.contexts.push(WasiCtx::default());
616///     }
617///     let mut store = Store::new(&engine, my_state);
618///
619///     // ... use `linker` to instantiate within `store` ...
620///
621///     Ok(())
622/// }
623///
624/// #[derive(Default)]
625/// struct MyState {
626///     table: ResourceTable,
627///     contexts: Vec<WasiCtx>,
628/// }
629///
630/// impl WasiNamedView for MyState {
631///     fn ctx(&mut self, id: NamedId) -> WasiCtxView<'_> {
632///         WasiCtxView {
633///             ctx: &mut self.contexts[id.0],
634///             table: &mut self.table,
635///         }
636///     }
637/// }
638/// ```
639pub fn add_named_to_linker_async<T>(
640    linker: &mut Linker<T>,
641    component: &Component,
642    lookup: impl FnMut(Interface, &str) -> wasmtime::Result<NamedId>,
643) -> wasmtime::Result<()>
644where
645    T: WasiNamedView,
646{
647    let options = bindings::LinkOptions::default();
648    add_named_to_linker_with_options_async(linker, &options, component, lookup)
649}
650
651/// Same as [`add_named_to_linker_async`] except [`bindings::LinkOptions`]
652/// can be specified to configure interfaces that are added.
653pub fn add_named_to_linker_with_options_async<T>(
654    linker: &mut Linker<T>,
655    options: &bindings::LinkOptions,
656    component: &Component,
657    mut lookup: impl FnMut(Interface, &str) -> wasmtime::Result<NamedId>,
658) -> wasmtime::Result<()>
659where
660    T: WasiNamedView,
661{
662    use crate::p2::bindings::named_imports::wasi::{cli, clocks, filesystem, random, sockets};
663
664    let l = linker;
665    clocks::wall_clock::add_to_linker::<T, WasiClocksNamed<T>>(
666        l,
667        component,
668        |name| lookup(Interface::ClocksWallClock, name),
669        |x| WasiCtxNamedView(x),
670    )?;
671    clocks::monotonic_clock::add_to_linker::<T, WasiClocksNamed<T>>(
672        l,
673        component,
674        |name| lookup(Interface::ClocksMonotonicClock, name),
675        |x| WasiCtxNamedView(x),
676    )?;
677    filesystem::types::add_to_linker::<T, WasiFilesystemNamed<T>>(
678        l,
679        component,
680        |name| lookup(Interface::FilesystemTypes, name),
681        |x| WasiCtxNamedView(x),
682    )?;
683    filesystem::preopens::add_to_linker::<T, WasiFilesystemNamed<T>>(
684        l,
685        component,
686        |name| lookup(Interface::FilesystemPreopens, name),
687        |x| WasiCtxNamedView(x),
688    )?;
689    random::random::add_to_linker::<T, WasiRandomNamed<T>>(
690        l,
691        component,
692        |name| lookup(Interface::RandomRandom, name),
693        |x| WasiCtxNamedView(x),
694    )?;
695    random::insecure::add_to_linker::<T, WasiRandomNamed<T>>(
696        l,
697        component,
698        |name| lookup(Interface::RandomInsecure, name),
699        |x| WasiCtxNamedView(x),
700    )?;
701    random::insecure_seed::add_to_linker::<T, WasiRandomNamed<T>>(
702        l,
703        component,
704        |name| lookup(Interface::RandomInsecureSeed, name),
705        |x| WasiCtxNamedView(x),
706    )?;
707    cli::exit::add_to_linker::<T, WasiCliNamed<T>>(
708        l,
709        component,
710        |name| lookup(Interface::CliExit, name),
711        |x| WasiCtxNamedView(x),
712    )?;
713    cli::environment::add_to_linker::<T, WasiCliNamed<T>>(
714        l,
715        component,
716        |name| lookup(Interface::CliEnvironment, name),
717        |x| WasiCtxNamedView(x),
718    )?;
719    cli::stdin::add_to_linker::<T, WasiCliNamed<T>>(
720        l,
721        component,
722        |name| lookup(Interface::CliStdin, name),
723        |x| WasiCtxNamedView(x),
724    )?;
725    cli::stdout::add_to_linker::<T, WasiCliNamed<T>>(
726        l,
727        component,
728        |name| lookup(Interface::CliStdout, name),
729        |x| WasiCtxNamedView(x),
730    )?;
731    cli::stderr::add_to_linker::<T, WasiCliNamed<T>>(
732        l,
733        component,
734        |name| lookup(Interface::CliStderr, name),
735        |x| WasiCtxNamedView(x),
736    )?;
737    cli::terminal_input::add_to_linker::<T, WasiCliNamed<T>>(
738        l,
739        component,
740        |name| lookup(Interface::CliTerminalInput, name),
741        |x| WasiCtxNamedView(x),
742    )?;
743    cli::terminal_output::add_to_linker::<T, WasiCliNamed<T>>(
744        l,
745        component,
746        |name| lookup(Interface::CliTerminalOutput, name),
747        |x| WasiCtxNamedView(x),
748    )?;
749    cli::terminal_stdin::add_to_linker::<T, WasiCliNamed<T>>(
750        l,
751        component,
752        |name| lookup(Interface::CliTerminalStdin, name),
753        |x| WasiCtxNamedView(x),
754    )?;
755    cli::terminal_stdout::add_to_linker::<T, WasiCliNamed<T>>(
756        l,
757        component,
758        |name| lookup(Interface::CliTerminalStdout, name),
759        |x| WasiCtxNamedView(x),
760    )?;
761    cli::terminal_stderr::add_to_linker::<T, WasiCliNamed<T>>(
762        l,
763        component,
764        |name| lookup(Interface::CliTerminalStderr, name),
765        |x| WasiCtxNamedView(x),
766    )?;
767    sockets::instance_network::add_to_linker::<T, WasiSocketsNamed<T>>(
768        l,
769        component,
770        |name| lookup(Interface::SocketsInstanceNetwork, name),
771        |x| WasiCtxNamedView(x),
772    )?;
773    sockets::network::add_to_linker::<T, WasiSocketsNamed<T>>(
774        l,
775        component,
776        |name| lookup(Interface::SocketsNetwork, name),
777        &options.into(),
778        |x| WasiCtxNamedView(x),
779    )?;
780    sockets::ip_name_lookup::add_to_linker::<T, WasiSocketsNamed<T>>(
781        l,
782        component,
783        |name| lookup(Interface::SocketsIpNameLookup, name),
784        |x| WasiCtxNamedView(x),
785    )?;
786    sockets::tcp_create_socket::add_to_linker::<T, WasiSocketsNamed<T>>(
787        l,
788        component,
789        |name| lookup(Interface::SocketsTcpCreateSocket, name),
790        |x| WasiCtxNamedView(x),
791    )?;
792    sockets::tcp::add_to_linker::<T, WasiSocketsNamed<T>>(
793        l,
794        component,
795        |name| lookup(Interface::SocketsTcp, name),
796        |x| WasiCtxNamedView(x),
797    )?;
798    sockets::udp_create_socket::add_to_linker::<T, WasiSocketsNamed<T>>(
799        l,
800        component,
801        |name| lookup(Interface::SocketsUdpCreateSocket, name),
802        |x| WasiCtxNamedView(x),
803    )?;
804    sockets::udp::add_to_linker::<T, WasiSocketsNamed<T>>(
805        l,
806        component,
807        |name| lookup(Interface::SocketsUdp, name),
808        |x| WasiCtxNamedView(x),
809    )?;
810    Ok(())
811}