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