wasmtime/runtime/component/linker.rs
1#[cfg(feature = "component-model-async")]
2use crate::component::concurrent::Accessor;
3use crate::component::func::HostFunc;
4use crate::component::instance::RuntimeImport;
5use crate::component::matching::{InstanceType, TypeChecker};
6use crate::component::types;
7use crate::component::{
8 Component, ComponentNamedList, Instance, InstancePre, Lift, Lower, ResourceType, Val,
9};
10use crate::hash_map::HashMap;
11use crate::prelude::*;
12use crate::{AsContextMut, Engine, Module, StoreContextMut};
13use alloc::sync::Arc;
14use core::marker;
15#[cfg(feature = "async")]
16use core::{future::Future, pin::Pin};
17use wasmtime_environ::PrimaryMap;
18use wasmtime_environ::component::{NameMap, NameMapIntern};
19
20/// A type used to instantiate [`Component`]s.
21///
22/// This type is used to both link components together as well as supply host
23/// functionality to components. Values are defined in a [`Linker`] by their
24/// import name and then components are instantiated with a [`Linker`] using the
25/// names provided for name resolution of the component's imports.
26///
27/// # Names and Semver
28///
29/// Names defined in a [`Linker`] correspond to import names in the Component
30/// Model. Names in the Component Model are allowed to be semver-qualified, for
31/// example:
32///
33/// * `wasi:cli/stdout@0.2.0`
34/// * `wasi:http/types@0.2.0-rc-2023-10-25`
35/// * `my:custom/plugin@1.0.0-pre.2`
36///
37/// These version strings are taken into account when looking up names within a
38/// [`Linker`]. You're allowed to define any number of versions within a
39/// [`Linker`] still, for example you can define `a:b/c@0.2.0`, `a:b/c@0.2.1`,
40/// and `a:b/c@0.3.0` all at the same time.
41///
42/// Specifically though when names are looked up within a linker, for example
43/// during instantiation, semver-compatible names are automatically consulted.
44/// This means that if you define `a:b/c@0.2.1` in a [`Linker`] but a component
45/// imports `a:b/c@0.2.0` then that import will resolve to the `0.2.1` version.
46///
47/// This lookup behavior relies on hosts being well-behaved when using Semver,
48/// specifically that interfaces once defined are never changed. This reflects
49/// how Semver works at the Component Model layer, and it's assumed that if
50/// versions are present then hosts are respecting this.
51///
52/// Note that this behavior goes the other direction, too. If a component
53/// imports `a:b/c@0.2.1` and the host has provided `a:b/c@0.2.0` then that
54/// will also resolve correctly. This is because if an API was defined at 0.2.0
55/// and 0.2.1 then it must be the same API.
56///
57/// This behavior is intended to make it easier for hosts to upgrade WASI and
58/// for guests to upgrade WASI. So long as the actual "meat" of the
59/// functionality is defined then it should align correctly and components can
60/// be instantiated.
61pub struct Linker<T: 'static> {
62 engine: Engine,
63 strings: Strings,
64 map: NameMap<usize, Definition>,
65 path: Vec<usize>,
66 allow_shadowing: bool,
67 _marker: marker::PhantomData<fn() -> T>,
68}
69
70impl<T: 'static> Clone for Linker<T> {
71 fn clone(&self) -> Linker<T> {
72 Linker {
73 engine: self.engine.clone(),
74 strings: self.strings.clone(),
75 map: self.map.clone(),
76 path: self.path.clone(),
77 allow_shadowing: self.allow_shadowing,
78 _marker: self._marker,
79 }
80 }
81}
82
83#[derive(Clone, Default)]
84pub struct Strings {
85 string2idx: HashMap<Arc<str>, usize>,
86 strings: Vec<Arc<str>>,
87}
88
89/// Structure representing an "instance" being defined within a linker.
90///
91/// Instances do not need to be actual [`Instance`]s and instead are defined by
92/// a "bag of named items", so each [`LinkerInstance`] can further define items
93/// internally.
94pub struct LinkerInstance<'a, T: 'static> {
95 engine: &'a Engine,
96 path: &'a mut Vec<usize>,
97 path_len: usize,
98 strings: &'a mut Strings,
99 map: &'a mut NameMap<usize, Definition>,
100 allow_shadowing: bool,
101 _marker: marker::PhantomData<fn() -> T>,
102}
103
104#[derive(Clone, Debug)]
105pub(crate) enum Definition {
106 Instance(NameMap<usize, Definition>),
107 Func(Arc<HostFunc>),
108 Module(Module),
109 Resource(ResourceType, Arc<crate::func::HostFunc>),
110}
111
112impl<T: 'static> Linker<T> {
113 /// Creates a new linker for the [`Engine`] specified with no items defined
114 /// within it.
115 pub fn new(engine: &Engine) -> Linker<T> {
116 Linker {
117 engine: engine.clone(),
118 strings: Strings::default(),
119 map: NameMap::default(),
120 allow_shadowing: false,
121 path: Vec::new(),
122 _marker: marker::PhantomData,
123 }
124 }
125
126 /// Returns the [`Engine`] this is connected to.
127 pub fn engine(&self) -> &Engine {
128 &self.engine
129 }
130
131 /// Configures whether or not name-shadowing is allowed.
132 ///
133 /// By default name shadowing is not allowed and it's an error to redefine
134 /// the same name within a linker.
135 pub fn allow_shadowing(&mut self, allow: bool) -> &mut Self {
136 self.allow_shadowing = allow;
137 self
138 }
139
140 /// Returns the "root instance" of this linker, used to define names into
141 /// the root namespace.
142 pub fn root(&mut self) -> LinkerInstance<'_, T> {
143 LinkerInstance {
144 engine: &self.engine,
145 path: &mut self.path,
146 path_len: 0,
147 strings: &mut self.strings,
148 map: &mut self.map,
149 allow_shadowing: self.allow_shadowing,
150 _marker: self._marker,
151 }
152 }
153
154 /// Returns a builder for the named instance specified.
155 ///
156 /// # Errors
157 ///
158 /// Returns an error if `name` is already defined within the linker.
159 pub fn instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>> {
160 self.root().into_instance(name)
161 }
162
163 fn typecheck<'a>(&'a self, component: &'a Component) -> Result<TypeChecker<'a>> {
164 let mut cx = TypeChecker {
165 engine: &self.engine,
166 types: component.types(),
167 strings: &self.strings,
168 imported_resources: Default::default(),
169 };
170
171 // Walk over the component's list of import names and use that to lookup
172 // the definition within this linker that it corresponds to. When found
173 // perform a typecheck against the component's expected type.
174 let env_component = component.env_component();
175 for (_idx, (name, ty)) in env_component.import_types.iter() {
176 let import = self.map.get(name, &self.strings);
177 cx.definition(ty, import)
178 .with_context(|| format!("component imports {desc} `{name}`, but a matching implementation was not found in the linker", desc = ty.desc()))?;
179 }
180 Ok(cx)
181 }
182
183 /// Returns the [`types::Component`] corresponding to `component` with resource
184 /// types imported by it replaced using imports present in [`Self`].
185 pub fn substituted_component_type(&self, component: &Component) -> Result<types::Component> {
186 let cx = self.typecheck(&component)?;
187 Ok(types::Component::from(
188 component.ty(),
189 &InstanceType {
190 types: cx.types,
191 resources: &cx.imported_resources,
192 },
193 ))
194 }
195
196 /// Performs a "pre-instantiation" to resolve the imports of the
197 /// [`Component`] specified with the items defined within this linker.
198 ///
199 /// This method will perform as much work as possible short of actually
200 /// instantiating an instance. Internally this will use the names defined
201 /// within this linker to satisfy the imports of the [`Component`] provided.
202 /// Additionally this will perform type-checks against the component's
203 /// imports against all items defined within this linker.
204 ///
205 /// Note that unlike internally in components where subtyping at the
206 /// interface-types layer is supported this is not supported here. Items
207 /// defined in this linker must match the component's imports precisely.
208 ///
209 /// # Errors
210 ///
211 /// Returns an error if this linker doesn't define a name that the
212 /// `component` imports or if a name defined doesn't match the type of the
213 /// item imported by the `component` provided.
214 pub fn instantiate_pre(&self, component: &Component) -> Result<InstancePre<T>> {
215 let cx = self.typecheck(&component)?;
216
217 // A successful typecheck resolves all of the imported resources used by
218 // this InstancePre. We keep a clone of this table in the InstancePre
219 // so that we can construct an InstanceType for typechecking.
220 let imported_resources = cx.imported_resources.clone();
221
222 // Now that all imports are known to be defined and satisfied by this
223 // linker a list of "flat" import items (aka no instances) is created
224 // using the import map within the component created at
225 // component-compile-time.
226 let env_component = component.env_component();
227 let mut imports = PrimaryMap::with_capacity(env_component.imports.len());
228 for (idx, (import, names)) in env_component.imports.iter() {
229 let (root, _) = &env_component.import_types[*import];
230
231 // This is the flattening process where we go from a definition
232 // optionally through a list of exported names to get to the final
233 // item.
234 let mut cur = self.map.get(root, &self.strings).unwrap();
235 for name in names {
236 cur = match cur {
237 Definition::Instance(map) => map.get(&name, &self.strings).unwrap(),
238 _ => unreachable!(),
239 };
240 }
241 let import = match cur {
242 Definition::Module(m) => RuntimeImport::Module(m.clone()),
243 Definition::Func(f) => RuntimeImport::Func(f.clone()),
244 Definition::Resource(t, dtor) => RuntimeImport::Resource {
245 ty: *t,
246 _dtor: dtor.clone(),
247 dtor_funcref: component.resource_drop_func_ref(dtor),
248 },
249
250 // This is guaranteed by the compilation process that "leaf"
251 // runtime imports are never instances.
252 Definition::Instance(_) => unreachable!(),
253 };
254 let i = imports.push(import);
255 assert_eq!(i, idx);
256 }
257 Ok(unsafe {
258 InstancePre::new_unchecked(component.clone(), Arc::new(imports), imported_resources)
259 })
260 }
261
262 /// Instantiates the [`Component`] provided into the `store` specified.
263 ///
264 /// This function will use the items defined within this [`Linker`] to
265 /// satisfy the imports of the [`Component`] provided as necessary. For more
266 /// information about this see [`Linker::instantiate_pre`] as well.
267 ///
268 /// # Errors
269 ///
270 /// Returns an error if this [`Linker`] doesn't define an import that
271 /// `component` requires or if it is of the wrong type. Additionally this
272 /// can return an error if something goes wrong during instantiation such as
273 /// a runtime trap or a runtime limit being exceeded.
274 pub fn instantiate(
275 &self,
276 store: impl AsContextMut<Data = T>,
277 component: &Component,
278 ) -> Result<Instance> {
279 assert!(
280 !store.as_context().async_support(),
281 "must use async instantiation when async support is enabled"
282 );
283 self.instantiate_pre(component)?.instantiate(store)
284 }
285
286 /// Instantiates the [`Component`] provided into the `store` specified.
287 ///
288 /// This is exactly like [`Linker::instantiate`] except for async stores.
289 ///
290 /// # Errors
291 ///
292 /// Returns an error if this [`Linker`] doesn't define an import that
293 /// `component` requires or if it is of the wrong type. Additionally this
294 /// can return an error if something goes wrong during instantiation such as
295 /// a runtime trap or a runtime limit being exceeded.
296 #[cfg(feature = "async")]
297 pub async fn instantiate_async(
298 &self,
299 store: impl AsContextMut<Data = T>,
300 component: &Component,
301 ) -> Result<Instance>
302 where
303 T: Send,
304 {
305 assert!(
306 store.as_context().async_support(),
307 "must use sync instantiation when async support is disabled"
308 );
309 self.instantiate_pre(component)?
310 .instantiate_async(store)
311 .await
312 }
313
314 /// Implement any imports of the given [`Component`] with a function which traps.
315 ///
316 /// By default a [`Linker`] will error when unknown imports are encountered when instantiating a [`Component`].
317 /// This changes this behavior from an instant error to a trap that will happen if the import is called.
318 pub fn define_unknown_imports_as_traps(&mut self, component: &Component) -> Result<()> {
319 use wasmtime_environ::component::ComponentTypes;
320 use wasmtime_environ::component::TypeDef;
321 // Recursively stub out all imports of the component with a function that traps.
322 fn stub_item<T>(
323 linker: &mut LinkerInstance<T>,
324 item_name: &str,
325 item_def: &TypeDef,
326 parent_instance: Option<&str>,
327 types: &ComponentTypes,
328 ) -> Result<()> {
329 // Skip if the item isn't an instance and has already been defined in the linker.
330 if !matches!(item_def, TypeDef::ComponentInstance(_)) && linker.get(item_name).is_some()
331 {
332 return Ok(());
333 }
334
335 match item_def {
336 TypeDef::ComponentFunc(_) => {
337 let fully_qualified_name = parent_instance
338 .map(|parent| format!("{parent}#{item_name}"))
339 .unwrap_or_else(|| item_name.to_owned());
340 linker.func_new(&item_name, move |_, _, _| {
341 bail!("unknown import: `{fully_qualified_name}` has not been defined")
342 })?;
343 }
344 TypeDef::ComponentInstance(i) => {
345 let instance = &types[*i];
346 let mut linker_instance = linker.instance(item_name)?;
347 for (export_name, export) in instance.exports.iter() {
348 stub_item(
349 &mut linker_instance,
350 export_name,
351 export,
352 Some(item_name),
353 types,
354 )?;
355 }
356 }
357 TypeDef::Resource(_) => {
358 let ty = crate::component::ResourceType::host::<()>();
359 linker.resource(item_name, ty, |_, _| Ok(()))?;
360 }
361 TypeDef::Component(_) | TypeDef::Module(_) => {
362 bail!("unable to define {} imports as traps", item_def.desc())
363 }
364 _ => {}
365 }
366 Ok(())
367 }
368
369 for (_, (import_name, import_type)) in &component.env_component().import_types {
370 stub_item(
371 &mut self.root(),
372 import_name,
373 import_type,
374 None,
375 component.types(),
376 )?;
377 }
378 Ok(())
379 }
380}
381
382impl<T: 'static> LinkerInstance<'_, T> {
383 fn as_mut(&mut self) -> LinkerInstance<'_, T> {
384 LinkerInstance {
385 engine: self.engine,
386 path: self.path,
387 path_len: self.path_len,
388 strings: self.strings,
389 map: self.map,
390 allow_shadowing: self.allow_shadowing,
391 _marker: self._marker,
392 }
393 }
394
395 /// Defines a new host-provided function into this [`LinkerInstance`].
396 ///
397 /// This method is used to give host functions to wasm components. The
398 /// `func` provided will be callable from linked components with the type
399 /// signature dictated by `Params` and `Return`. The `Params` is a tuple of
400 /// types that will come from wasm and `Return` is a value coming from the
401 /// host going back to wasm.
402 ///
403 /// Additionally the `func` takes a
404 /// [`StoreContextMut`](crate::StoreContextMut) as its first parameter.
405 ///
406 /// Note that `func` must be an `Fn` and must also be `Send + Sync +
407 /// 'static`. Shared state within a func is typically accessed with the `T`
408 /// type parameter from [`Store<T>`](crate::Store) which is accessible
409 /// through the leading [`StoreContextMut<'_, T>`](crate::StoreContextMut)
410 /// argument which can be provided to the `func` given here.
411 ///
412 /// # Blocking / Async Behavior
413 ///
414 /// The host function `func` provided here is a blocking function from the
415 /// perspective of WebAssembly, regardless of how [`Config::async_support`]
416 /// is defined. This function can be used both with sync and async stores
417 /// and will always define a blocking function.
418 ///
419 /// To define a function which is async on the host, but blocking to the
420 /// guest, see the [`func_wrap_async`] method.
421 ///
422 /// [`Config::async_support`]: crate::Config::async_support
423 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async
424 //
425 // TODO: needs more words and examples
426 pub fn func_wrap<F, Params, Return>(&mut self, name: &str, func: F) -> Result<()>
427 where
428 F: Fn(StoreContextMut<T>, Params) -> Result<Return> + Send + Sync + 'static,
429 Params: ComponentNamedList + Lift + 'static,
430 Return: ComponentNamedList + Lower + 'static,
431 {
432 self.insert(name, Definition::Func(HostFunc::from_closure(func)))?;
433 Ok(())
434 }
435
436 /// Defines a new host-provided async function into this [`LinkerInstance`].
437 ///
438 /// This function is similar to [`Self::func_wrap`] except it takes an async
439 /// host function instead of a blocking host function. The `F` function here
440 /// is intended to be:
441 ///
442 /// ```ignore
443 /// F: AsyncFn(StoreContextMut<'_, T>, Params) -> Result<Return>
444 /// ```
445 ///
446 /// however the returned future must be `Send` which is not possible to
447 /// bound at this time. This will be switched to an async closure once Rust
448 /// supports it.
449 ///
450 /// # Blocking / Async Behavior
451 ///
452 /// This function can only be called when [`Config::async_support`] is
453 /// enabled. The function defined which WebAssembly calls will still appear
454 /// as blocking from the perspective of WebAssembly itself. The host,
455 /// however, can perform asynchronous operations without blocking the thread
456 /// performing a call.
457 ///
458 /// When [`Config::async_support`] is enabled then all WebAssembly is
459 /// invoked on a separate stack within a Wasmtime-managed fiber. This means
460 /// that if the future returned by `F` is not immediately ready then the
461 /// fiber will be suspended to block WebAssembly but not the host. When the
462 /// future becomes ready again the fiber will be resumed to continue
463 /// execution within WebAssembly.
464 ///
465 /// # Panics
466 ///
467 /// This function panics if [`Config::async_support`] is set to `false`.
468 ///
469 /// [`Config::async_support`]: crate::Config::async_support
470 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async
471 #[cfg(feature = "async")]
472 pub fn func_wrap_async<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()>
473 where
474 F: Fn(
475 StoreContextMut<'_, T>,
476 Params,
477 ) -> Box<dyn Future<Output = Result<Return>> + Send + '_>
478 + Send
479 + Sync
480 + 'static,
481 Params: ComponentNamedList + Lift + 'static,
482 Return: ComponentNamedList + Lower + 'static,
483 {
484 assert!(
485 self.engine.config().async_support,
486 "cannot use `func_wrap_async` without enabling async support in the config"
487 );
488 let ff = move |store: StoreContextMut<'_, T>, params: Params| -> Result<Return> {
489 store.block_on(|store| f(store, params).into())?
490 };
491 self.func_wrap(name, ff)
492 }
493
494 /// Defines a new host-provided async function into this [`LinkerInstance`].
495 ///
496 /// This function defines a host function available to call from
497 /// WebAssembly. WebAssembly may additionally make multiple invocations of
498 /// this function concurrently all at the same time. This function requires
499 /// the [`Config::wasm_component_model_async`] feature to be enabled.
500 ///
501 /// The function `f` provided will be invoked when called by WebAssembly.
502 /// WebAssembly components may then call `f` multiple times while previous
503 /// invocations of `f` are already running. Additionally while `f` is
504 /// running other host functions may be invoked.
505 ///
506 /// The `F` function here is intended to be:
507 ///
508 /// ```ignore
509 /// F: AsyncFn(&Accessor<T>, Params) -> Result<Return>
510 /// ```
511 ///
512 /// however the returned future must be `Send` which is not possible to
513 /// bound at this time. This will be switched to an async closure once Rust
514 /// supports it.
515 ///
516 /// The closure `f` is provided an [`Accessor`] which can be used to acquire
517 /// temporary, blocking, access to a [`StoreContextMut`] (through
518 /// [`Access`]). This models how a store is not available to `f` across
519 /// `await` points but it is temporarily available while actively being
520 /// polled.
521 ///
522 /// # Blocking / Async Behavior
523 ///
524 /// This function can only be called when [`Config::async_support`] is
525 /// enabled. Unlike [`Self::func_wrap`] and [`Self::func_wrap_async`] this
526 /// function is asynchronous even from the perspective of guest WebAssembly.
527 /// This means that if `f` is not immediately resolved then the call from
528 /// WebAssembly will still return immediately (assuming it was lowered with
529 /// `async`). The closure `f` should not block the current thread and should
530 /// only perform blocking via `async` meaning that `f` won't block either
531 /// WebAssembly nor the host.
532 ///
533 /// Note that WebAssembly components can lower host functions both with and
534 /// without `async`. That means that even if a host function is defined in
535 /// the "concurrent" mode here a guest may still lower it synchronously. In
536 /// this situation Wasmtime will manage blocking the guest while the closure
537 /// `f` provided here completes. If a guest lowers this function with
538 /// `async`, though, then no blocking will happen.
539 ///
540 /// # Panics
541 ///
542 /// This function panics if [`Config::async_support`] is set to `false`.
543 ///
544 /// [`Config::async_support`]: crate::Config::async_support
545 /// [`Config::wasm_component_model_async`]: crate::Config::wasm_component_model_async
546 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async
547 #[cfg(feature = "component-model-async")]
548 pub fn func_wrap_concurrent<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()>
549 where
550 T: 'static,
551 F: Fn(&Accessor<T>, Params) -> Pin<Box<dyn Future<Output = Result<Return>> + Send + '_>>
552 + Send
553 + Sync
554 + 'static,
555 Params: ComponentNamedList + Lift + 'static,
556 Return: ComponentNamedList + Lower + 'static,
557 {
558 assert!(
559 self.engine.config().async_support,
560 "cannot use `func_wrap_concurrent` without enabling async support in the config"
561 );
562 self.insert(name, Definition::Func(HostFunc::from_concurrent(f)))?;
563 Ok(())
564 }
565
566 /// Define a new host-provided function using dynamically typed values.
567 ///
568 /// The `name` provided is the name of the function to define and the
569 /// `func` provided is the host-defined closure to invoke when this
570 /// function is called.
571 ///
572 /// This function is the "dynamic" version of defining a host function as
573 /// compared to [`LinkerInstance::func_wrap`]. With
574 /// [`LinkerInstance::func_wrap`] a function's type is statically known but
575 /// with this method the `func` argument's type isn't known ahead of time.
576 /// That means that `func` can be by imported component so long as it's
577 /// imported as a matching name.
578 ///
579 /// Type information will be available at execution time, however. For
580 /// example when `func` is invoked the second argument, a `&[Val]` list,
581 /// contains [`Val`] entries that say what type they are. Additionally the
582 /// third argument, `&mut [Val]`, is the expected number of results. Note
583 /// that the expected types of the results cannot be learned during the
584 /// execution of `func`. Learning that would require runtime introspection
585 /// of a component.
586 ///
587 /// Return values, stored in the third argument of `&mut [Val]`, are
588 /// type-checked at runtime to ensure that they have the appropriate type.
589 /// A trap will be raised if they do not have the right type.
590 ///
591 /// # Examples
592 ///
593 /// ```
594 /// use wasmtime::{Store, Engine};
595 /// use wasmtime::component::{Component, Linker, Val};
596 ///
597 /// # fn main() -> wasmtime::Result<()> {
598 /// let engine = Engine::default();
599 /// let component = Component::new(
600 /// &engine,
601 /// r#"
602 /// (component
603 /// (import "thunk" (func $thunk))
604 /// (import "is-even" (func $is-even (param "x" u32) (result bool)))
605 ///
606 /// (core module $m
607 /// (import "" "thunk" (func $thunk))
608 /// (import "" "is-even" (func $is-even (param i32) (result i32)))
609 ///
610 /// (func (export "run")
611 /// call $thunk
612 ///
613 /// (call $is-even (i32.const 1))
614 /// if unreachable end
615 ///
616 /// (call $is-even (i32.const 2))
617 /// i32.eqz
618 /// if unreachable end
619 /// )
620 /// )
621 /// (core func $thunk (canon lower (func $thunk)))
622 /// (core func $is-even (canon lower (func $is-even)))
623 /// (core instance $i (instantiate $m
624 /// (with "" (instance
625 /// (export "thunk" (func $thunk))
626 /// (export "is-even" (func $is-even))
627 /// ))
628 /// ))
629 ///
630 /// (func (export "run") (canon lift (core func $i "run")))
631 /// )
632 /// "#,
633 /// )?;
634 ///
635 /// let mut linker = Linker::<()>::new(&engine);
636 ///
637 /// // Sample function that takes no arguments.
638 /// linker.root().func_new("thunk", |_store, params, results| {
639 /// assert!(params.is_empty());
640 /// assert!(results.is_empty());
641 /// println!("Look ma, host hands!");
642 /// Ok(())
643 /// })?;
644 ///
645 /// // This function takes one argument and returns one result.
646 /// linker.root().func_new("is-even", |_store, params, results| {
647 /// assert_eq!(params.len(), 1);
648 /// let param = match params[0] {
649 /// Val::U32(n) => n,
650 /// _ => panic!("unexpected type"),
651 /// };
652 ///
653 /// assert_eq!(results.len(), 1);
654 /// results[0] = Val::Bool(param % 2 == 0);
655 /// Ok(())
656 /// })?;
657 ///
658 /// let mut store = Store::new(&engine, ());
659 /// let instance = linker.instantiate(&mut store, &component)?;
660 /// let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
661 /// run.call(&mut store, ())?;
662 /// # Ok(())
663 /// # }
664 /// ```
665 pub fn func_new(
666 &mut self,
667 name: &str,
668 func: impl Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static,
669 ) -> Result<()> {
670 self.insert(name, Definition::Func(HostFunc::new_dynamic(func)))?;
671 Ok(())
672 }
673
674 /// Define a new host-provided async function using dynamic types.
675 ///
676 /// As [`Self::func_wrap_async`] is a dual of [`Self::func_wrap`], this
677 /// function is the dual of [`Self::func_new`].
678 ///
679 /// For documentation on blocking behavior see [`Self::func_wrap_async`].
680 #[cfg(feature = "async")]
681 pub fn func_new_async<F>(&mut self, name: &str, f: F) -> Result<()>
682 where
683 F: for<'a> Fn(
684 StoreContextMut<'a, T>,
685 &'a [Val],
686 &'a mut [Val],
687 ) -> Box<dyn Future<Output = Result<()>> + Send + 'a>
688 + Send
689 + Sync
690 + 'static,
691 {
692 assert!(
693 self.engine.config().async_support,
694 "cannot use `func_new_async` without enabling async support in the config"
695 );
696 let ff = move |store: StoreContextMut<'_, T>, params: &[Val], results: &mut [Val]| {
697 store.with_blocking(|store, cx| cx.block_on(Pin::from(f(store, params, results)))?)
698 };
699 return self.func_new(name, ff);
700 }
701
702 /// Define a new host-provided async function using dynamic types.
703 ///
704 /// As [`Self::func_wrap_concurrent`] is a dual of [`Self::func_wrap`], this
705 /// function is the dual of [`Self::func_new`].
706 ///
707 /// For documentation on async/blocking behavior see
708 /// [`Self::func_wrap_concurrent`].
709 #[cfg(feature = "component-model-async")]
710 pub fn func_new_concurrent<F>(&mut self, name: &str, f: F) -> Result<()>
711 where
712 T: 'static,
713 F: for<'a> Fn(
714 &'a Accessor<T>,
715 &'a [Val],
716 &'a mut [Val],
717 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
718 + Send
719 + Sync
720 + 'static,
721 {
722 assert!(
723 self.engine.config().async_support,
724 "cannot use `func_wrap_concurrent` without enabling async support in the config"
725 );
726 self.insert(name, Definition::Func(HostFunc::new_dynamic_concurrent(f)))?;
727 Ok(())
728 }
729
730 /// Defines a [`Module`] within this instance.
731 ///
732 /// This can be used to provide a core wasm [`Module`] as an import to a
733 /// component. The [`Module`] provided is saved within the linker for the
734 /// specified `name` in this instance.
735 pub fn module(&mut self, name: &str, module: &Module) -> Result<()> {
736 self.insert(name, Definition::Module(module.clone()))?;
737 Ok(())
738 }
739
740 /// Defines a new resource of a given [`ResourceType`] in this linker.
741 ///
742 /// This function is used to specify resources defined in the host.
743 ///
744 /// The `name` argument is the name to define the resource within this
745 /// linker.
746 ///
747 /// The `dtor` provided is a destructor that will get invoked when an owned
748 /// version of this resource is destroyed from the guest. Note that this
749 /// destructor is not called when a host-owned resource is destroyed as it's
750 /// assumed the host knows how to handle destroying its own resources.
751 ///
752 /// The `dtor` closure is provided the store state as the first argument
753 /// along with the representation of the resource that was just destroyed.
754 ///
755 /// [`Resource<U>`]: crate::component::Resource
756 ///
757 /// # Errors
758 ///
759 /// The provided `dtor` closure returns an error if something goes wrong
760 /// when a guest calls the `dtor` to drop a `Resource<T>` such as
761 /// a runtime trap or a runtime limit being exceeded.
762 pub fn resource(
763 &mut self,
764 name: &str,
765 ty: ResourceType,
766 dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static,
767 ) -> Result<()> {
768 let dtor = Arc::new(crate::func::HostFunc::wrap_inner(
769 &self.engine,
770 move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.as_context_mut(), param),
771 ));
772 self.insert(name, Definition::Resource(ty, dtor))?;
773 Ok(())
774 }
775
776 /// Identical to [`Self::resource`], except that it takes an async destructor.
777 #[cfg(feature = "async")]
778 pub fn resource_async<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()>
779 where
780 F: Fn(StoreContextMut<'_, T>, u32) -> Box<dyn Future<Output = Result<()>> + Send + '_>
781 + Send
782 + Sync
783 + 'static,
784 {
785 assert!(
786 self.engine.config().async_support,
787 "cannot use `resource_async` without enabling async support in the config"
788 );
789 let dtor = Arc::new(crate::func::HostFunc::wrap_inner(
790 &self.engine,
791 move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| {
792 cx.as_context_mut()
793 .block_on(|store| dtor(store, param).into())?
794 },
795 ));
796 self.insert(name, Definition::Resource(ty, dtor))?;
797 Ok(())
798 }
799
800 /// Identical to [`Self::resource`], except that it takes a concurrent destructor.
801 #[cfg(feature = "component-model-async")]
802 pub fn resource_concurrent<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()>
803 where
804 T: Send + 'static,
805 F: Fn(&Accessor<T>, u32) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>>
806 + Send
807 + Sync
808 + 'static,
809 {
810 assert!(
811 self.engine.config().async_support,
812 "cannot use `resource_concurrent` without enabling async support in the config"
813 );
814 // TODO: This isn't really concurrent -- it requires exclusive access to
815 // the store for the duration of the call, preventing guest code from
816 // running until it completes. We should make it concurrent and clean
817 // up the implementation to avoid using e.g. `Accessor::new` and
818 // `tls::set` directly.
819 let dtor = Arc::new(dtor);
820 let dtor = Arc::new(crate::func::HostFunc::wrap_inner(
821 &self.engine,
822 move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| {
823 let dtor = dtor.clone();
824 cx.as_context_mut().block_on(move |mut store| {
825 Box::pin(async move {
826 // NOTE: We currently pass `None` as the `instance`
827 // parameter to `Accessor::new` because we don't have ready
828 // access to it, meaning `dtor` will panic if it tries to
829 // use `Accessor::instance`. We could plumb that through
830 // from the `wasmtime-cranelift`-generated code, but we plan
831 // to remove `Accessor::instance` once all instances in a
832 // store share the same concurrent state, at which point we
833 // won't need it anyway.
834 let accessor = &Accessor::new(
835 crate::store::StoreToken::new(store.as_context_mut()),
836 None,
837 );
838 let mut future = std::pin::pin!(dtor(accessor, param));
839 std::future::poll_fn(|cx| {
840 crate::component::concurrent::tls::set(store.0, || {
841 future.as_mut().poll(cx)
842 })
843 })
844 .await
845 })
846 })?
847 },
848 ));
849 self.insert(name, Definition::Resource(ty, dtor))?;
850 Ok(())
851 }
852
853 /// Defines a nested instance within this instance.
854 ///
855 /// This can be used to describe arbitrarily nested levels of instances
856 /// within a linker to satisfy nested instance exports of components.
857 pub fn instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>> {
858 self.as_mut().into_instance(name)
859 }
860
861 /// Same as [`LinkerInstance::instance`] except with different lifetime
862 /// parameters.
863 pub fn into_instance(mut self, name: &str) -> Result<Self> {
864 let name = self.insert(name, Definition::Instance(NameMap::default()))?;
865 self.map = match self.map.raw_get_mut(&name) {
866 Some(Definition::Instance(map)) => map,
867 _ => unreachable!(),
868 };
869 self.path.truncate(self.path_len);
870 self.path.push(name);
871 self.path_len += 1;
872 Ok(self)
873 }
874
875 fn insert(&mut self, name: &str, item: Definition) -> Result<usize> {
876 self.map
877 .insert(name, self.strings, self.allow_shadowing, item)
878 }
879
880 fn get(&self, name: &str) -> Option<&Definition> {
881 self.map.get(name, self.strings)
882 }
883}
884
885impl NameMapIntern for Strings {
886 type Key = usize;
887
888 fn intern(&mut self, string: &str) -> usize {
889 if let Some(idx) = self.string2idx.get(string) {
890 return *idx;
891 }
892 let string: Arc<str> = string.into();
893 let idx = self.strings.len();
894 self.strings.push(string.clone());
895 self.string2idx.insert(string, idx);
896 idx
897 }
898
899 fn lookup(&self, string: &str) -> Option<usize> {
900 self.string2idx.get(string).cloned()
901 }
902}