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