wasmtime_wasi/p3/sockets/mod.rs
1use crate::TrappableError;
2use crate::p3::Interface;
3use crate::p3::bindings::sockets::{ip_name_lookup, types};
4use crate::sockets::{WasiSockets, WasiSocketsNamed, WasiSocketsNamedView, WasiSocketsView};
5use crate::{NamedId, WasiCtxNamedView};
6use wasmtime::component::{Component, Linker};
7
8mod conv;
9mod host;
10
11pub type SocketResult<T> = Result<T, SocketError>;
12pub type SocketError = TrappableError<types::ErrorCode>;
13
14/// Add all WASI interfaces from this module into the `linker` provided.
15///
16/// This function will add all interfaces implemented by this module to the
17/// [`Linker`], which corresponds to the `wasi:sockets/imports` world supported by
18/// this module.
19///
20/// This is low-level API for advanced use cases,
21/// [`wasmtime_wasi::p3::add_to_linker`](crate::p3::add_to_linker) can be used instead
22/// to add *all* wasip3 interfaces (including the ones from this module) to the `linker`.
23///
24/// # Example
25///
26/// ```
27/// use wasmtime::{Engine, Result, Store, Config};
28/// use wasmtime::component::{Linker, ResourceTable};
29/// use wasmtime_wasi::sockets::{WasiSocketsCtx, WasiSocketsCtxView, WasiSocketsView};
30///
31/// fn main() -> Result<()> {
32/// let mut config = Config::new();
33/// config.wasm_component_model_async(true);
34/// let engine = Engine::new(&config)?;
35///
36/// let mut linker = Linker::<MyState>::new(&engine);
37/// wasmtime_wasi::p3::sockets::add_to_linker(&mut linker)?;
38/// // ... add any further functionality to `linker` if desired ...
39///
40/// let mut store = Store::new(
41/// &engine,
42/// MyState::default(),
43/// );
44///
45/// // ... use `linker` to instantiate within `store` ...
46///
47/// Ok(())
48/// }
49///
50/// #[derive(Default)]
51/// struct MyState {
52/// sockets: WasiSocketsCtx,
53/// table: ResourceTable,
54/// }
55///
56/// impl WasiSocketsView for MyState {
57/// fn sockets(&mut self) -> WasiSocketsCtxView<'_> {
58/// WasiSocketsCtxView {
59/// ctx: &mut self.sockets,
60/// table: &mut self.table,
61/// }
62/// }
63/// }
64/// ```
65pub fn add_to_linker<T>(linker: &mut Linker<T>) -> wasmtime::Result<()>
66where
67 T: WasiSocketsView + 'static,
68{
69 ip_name_lookup::add_to_linker::<_, WasiSockets>(linker, T::sockets)?;
70 types::add_to_linker::<_, WasiSockets>(linker, T::sockets)?;
71 Ok(())
72}
73
74/// Convenience function to add `wasi:sockets` interfaces into `linker` for any
75/// named imports of `wasi:sockets` interfaces.
76///
77/// This function is similar to [`add_to_linker`] except that it's specifically
78/// designed to work with named imports of `wasi:sockets` interfaces that
79/// components may have. This requires a [`Component`] parameter to be passed in
80/// when populating the [`Linker`] provided to see what the [`Component`]
81/// actually imports.
82///
83/// Like [`add_to_linker`] this is a bit low level and you may want to possibly
84/// invoke [`wasmtime_wasi::p3::add_named_to_linker`] instead. Alternatively if
85/// this isn't low level enough you can additionally invoke bindgen-generated
86/// `add_to_linker` functions directly from within the
87/// [`named_imports::wasi::sockets`] module.
88///
89/// [`wasmtime_wasi::p3::add_named_to_linker`]: crate::p3::add_named_to_linker
90/// [`named_imports::wasi::sockets`]: crate::p3::bindings::named_imports::wasi::sockets
91///
92/// The `lookup` function provided here is invoked for every named import found
93/// for a particular interface. The [`Interface`] given is what's being bound,
94/// and the `&str` argument is the name that the component imports it as. The
95/// embedder can then decide how it would like to allocate a [`NamedId`] for
96/// this import. If `Ok` is returned then the linker is populated with this
97/// name, and imported functions will pass the [`NamedId`] later to the
98/// implementation of [`WasiSocketsNamedView`] on `T` when invoked. If `Err` is
99/// returned then the error will cause this entire function to fail and this
100/// function call will return the same error.
101///
102/// # Example
103///
104/// ```
105/// use std::collections::HashMap;
106/// use wasmtime::component::{Component, Linker, ResourceTable};
107/// use wasmtime::{Engine, Result, Store, Config};
108/// use wasmtime_wasi::NamedId;
109/// use wasmtime_wasi::sockets::{WasiSocketsCtx, WasiSocketsCtxView, WasiSocketsNamedView};
110///
111/// fn main() -> Result<()> {
112/// let engine = Engine::default();
113/// let component = Component::new(&engine, "(component)")?;
114///
115/// let mut linker = Linker::<MyState>::new(&engine);
116///
117/// // ... add default functionality to `linker` as needed ...
118///
119/// // and then additionally fill in any specific named imports `component`
120/// // might have for `wasi:sockets` interfaces.
121/// let mut name_map = HashMap::new();
122/// wasmtime_wasi::p3::sockets::add_named_to_linker(&mut linker, &component, |_i, name| {
123/// let len = name_map.len();
124/// Ok(NamedId(*name_map.entry(name.to_string()).or_insert(len)))
125/// })?;
126///
127/// // Here a `WasiSocketsCtx` is allocated per-named-import and will then be
128/// // referred to internally by the [`NamedId`] allocated above. You could
129/// // also use `name_map` to configure each context differently.
130/// let mut my_state = MyState::default();
131/// for _ in 0..name_map.len() {
132/// my_state.contexts.push(WasiSocketsCtx::default());
133/// }
134/// let mut store = Store::new(&engine, my_state);
135/// let instance = linker.instantiate(&mut store, &component)?;
136///
137/// // ... work with `instance` ...
138///
139/// Ok(())
140/// }
141///
142/// #[derive(Default)]
143/// struct MyState {
144/// table: ResourceTable,
145/// contexts: Vec<WasiSocketsCtx>,
146/// }
147///
148/// impl WasiSocketsNamedView for MyState {
149/// fn sockets(&mut self, id: NamedId) -> WasiSocketsCtxView<'_> {
150/// WasiSocketsCtxView {
151/// ctx: &mut self.contexts[id.0],
152/// table: &mut self.table,
153/// }
154/// }
155/// }
156/// ```
157pub fn add_named_to_linker<T>(
158 linker: &mut Linker<T>,
159 component: &Component,
160 mut lookup: impl FnMut(Interface, &str) -> wasmtime::Result<NamedId>,
161) -> wasmtime::Result<()>
162where
163 T: WasiSocketsNamedView + 'static,
164{
165 use crate::p3::bindings::named_imports::wasi::sockets::{ip_name_lookup, types};
166 ip_name_lookup::add_to_linker::<_, WasiSocketsNamed<T>>(
167 linker,
168 component,
169 |name| lookup(Interface::SocketsIpNameLookup, name),
170 |x| WasiCtxNamedView(x),
171 )?;
172 types::add_to_linker::<_, WasiSocketsNamed<T>>(
173 linker,
174 component,
175 |name| lookup(Interface::SocketsTypes, name),
176 |x| WasiCtxNamedView(x),
177 )?;
178 Ok(())
179}