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 [`Linker`].
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    // TODO: needs more words and examples
413    pub fn func_wrap<F, Params, Return>(&mut self, name: &str, func: F) -> Result<()>
414    where
415        F: Fn(StoreContextMut<T>, Params) -> Result<Return> + Send + Sync + 'static,
416        Params: ComponentNamedList + Lift + 'static,
417        Return: ComponentNamedList + Lower + 'static,
418    {
419        self.insert(name, Definition::Func(HostFunc::from_closure(func)))?;
420        Ok(())
421    }
422
423    /// Defines a new host-provided async function into this [`Linker`].
424    ///
425    /// This is exactly like [`Self::func_wrap`] except it takes an async
426    /// host function.
427    #[cfg(feature = "async")]
428    pub fn func_wrap_async<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()>
429    where
430        F: for<'a> Fn(
431                StoreContextMut<'a, T>,
432                Params,
433            ) -> Box<dyn Future<Output = Result<Return>> + Send + 'a>
434            + Send
435            + Sync
436            + 'static,
437        Params: ComponentNamedList + Lift + 'static,
438        Return: ComponentNamedList + Lower + 'static,
439    {
440        assert!(
441            self.engine.config().async_support,
442            "cannot use `func_wrap_async` without enabling async support in the config"
443        );
444        let ff = move |store: StoreContextMut<'_, T>, params: Params| -> Result<Return> {
445            store.block_on(|store| f(store, params).into())?
446        };
447        self.func_wrap(name, ff)
448    }
449
450    /// Defines a new host-provided async function into this [`LinkerInstance`].
451    ///
452    /// This allows the caller to register host functions with the
453    /// LinkerInstance such that multiple calls to such functions can run
454    /// concurrently. This isn't possible with the existing func_wrap_async
455    /// method because it takes a function which returns a future that owns a
456    /// unique reference to the Store, meaning the Store can't be used for
457    /// anything else until the future resolves.
458    #[cfg(feature = "component-model-async")]
459    pub fn func_wrap_concurrent<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()>
460    where
461        T: 'static,
462        F: for<'a> Fn(
463                &'a mut Accessor<T>,
464                Params,
465            ) -> Pin<Box<dyn Future<Output = Result<Return>> + Send + 'a>>
466            + Send
467            + Sync
468            + 'static,
469        Params: ComponentNamedList + Lift + Send + Sync + 'static,
470        Return: ComponentNamedList + Lower + Send + Sync + 'static,
471    {
472        let _ = (name, f);
473        todo!()
474    }
475
476    /// Define a new host-provided function using dynamically typed values.
477    ///
478    /// The `name` provided is the name of the function to define and the
479    /// `func` provided is the host-defined closure to invoke when this
480    /// function is called.
481    ///
482    /// This function is the "dynamic" version of defining a host function as
483    /// compared to [`LinkerInstance::func_wrap`]. With
484    /// [`LinkerInstance::func_wrap`] a function's type is statically known but
485    /// with this method the `func` argument's type isn't known ahead of time.
486    /// That means that `func` can be by imported component so long as it's
487    /// imported as a matching name.
488    ///
489    /// Type information will be available at execution time, however. For
490    /// example when `func` is invoked the second argument, a `&[Val]` list,
491    /// contains [`Val`] entries that say what type they are. Additionally the
492    /// third argument, `&mut [Val]`, is the expected number of results. Note
493    /// that the expected types of the results cannot be learned during the
494    /// execution of `func`. Learning that would require runtime introspection
495    /// of a component.
496    ///
497    /// Return values, stored in the third argument of `&mut [Val]`, are
498    /// type-checked at runtime to ensure that they have the appropriate type.
499    /// A trap will be raised if they do not have the right type.
500    ///
501    /// # Examples
502    ///
503    /// ```
504    /// use wasmtime::{Store, Engine};
505    /// use wasmtime::component::{Component, Linker, Val};
506    ///
507    /// # fn main() -> wasmtime::Result<()> {
508    /// let engine = Engine::default();
509    /// let component = Component::new(
510    ///     &engine,
511    ///     r#"
512    ///         (component
513    ///             (import "thunk" (func $thunk))
514    ///             (import "is-even" (func $is-even (param "x" u32) (result bool)))
515    ///
516    ///             (core module $m
517    ///                 (import "" "thunk" (func $thunk))
518    ///                 (import "" "is-even" (func $is-even (param i32) (result i32)))
519    ///
520    ///                 (func (export "run")
521    ///                     call $thunk
522    ///
523    ///                     (call $is-even (i32.const 1))
524    ///                     if unreachable end
525    ///
526    ///                     (call $is-even (i32.const 2))
527    ///                     i32.eqz
528    ///                     if unreachable end
529    ///                 )
530    ///             )
531    ///             (core func $thunk (canon lower (func $thunk)))
532    ///             (core func $is-even (canon lower (func $is-even)))
533    ///             (core instance $i (instantiate $m
534    ///                 (with "" (instance
535    ///                     (export "thunk" (func $thunk))
536    ///                     (export "is-even" (func $is-even))
537    ///                 ))
538    ///             ))
539    ///
540    ///             (func (export "run") (canon lift (core func $i "run")))
541    ///         )
542    ///     "#,
543    /// )?;
544    ///
545    /// let mut linker = Linker::<()>::new(&engine);
546    ///
547    /// // Sample function that takes no arguments.
548    /// linker.root().func_new("thunk", |_store, params, results| {
549    ///     assert!(params.is_empty());
550    ///     assert!(results.is_empty());
551    ///     println!("Look ma, host hands!");
552    ///     Ok(())
553    /// })?;
554    ///
555    /// // This function takes one argument and returns one result.
556    /// linker.root().func_new("is-even", |_store, params, results| {
557    ///     assert_eq!(params.len(), 1);
558    ///     let param = match params[0] {
559    ///         Val::U32(n) => n,
560    ///         _ => panic!("unexpected type"),
561    ///     };
562    ///
563    ///     assert_eq!(results.len(), 1);
564    ///     results[0] = Val::Bool(param % 2 == 0);
565    ///     Ok(())
566    /// })?;
567    ///
568    /// let mut store = Store::new(&engine, ());
569    /// let instance = linker.instantiate(&mut store, &component)?;
570    /// let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
571    /// run.call(&mut store, ())?;
572    /// # Ok(())
573    /// # }
574    /// ```
575    pub fn func_new(
576        &mut self,
577        name: &str,
578        func: impl Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static,
579    ) -> Result<()> {
580        self.insert(name, Definition::Func(HostFunc::new_dynamic(func)))?;
581        Ok(())
582    }
583
584    /// Define a new host-provided async function using dynamic types.
585    ///
586    /// This is exactly like [`Self::func_new`] except it takes an async
587    /// host function.
588    #[cfg(feature = "async")]
589    pub fn func_new_async<F>(&mut self, name: &str, f: F) -> Result<()>
590    where
591        F: for<'a> Fn(
592                StoreContextMut<'a, T>,
593                &'a [Val],
594                &'a mut [Val],
595            ) -> Box<dyn Future<Output = Result<()>> + Send + 'a>
596            + Send
597            + Sync
598            + 'static,
599    {
600        assert!(
601            self.engine.config().async_support,
602            "cannot use `func_new_async` without enabling async support in the config"
603        );
604        let ff = move |store: StoreContextMut<'_, T>, params: &[Val], results: &mut [Val]| {
605            store.with_blocking(|store, cx| cx.block_on(Pin::from(f(store, params, results)))?)
606        };
607        return self.func_new(name, ff);
608    }
609
610    /// Defines a [`Module`] within this instance.
611    ///
612    /// This can be used to provide a core wasm [`Module`] as an import to a
613    /// component. The [`Module`] provided is saved within the linker for the
614    /// specified `name` in this instance.
615    pub fn module(&mut self, name: &str, module: &Module) -> Result<()> {
616        self.insert(name, Definition::Module(module.clone()))?;
617        Ok(())
618    }
619
620    /// Defines a new resource of a given [`ResourceType`] in this linker.
621    ///
622    /// This function is used to specify resources defined in the host.
623    ///
624    /// The `name` argument is the name to define the resource within this
625    /// linker.
626    ///
627    /// The `dtor` provided is a destructor that will get invoked when an owned
628    /// version of this resource is destroyed from the guest. Note that this
629    /// destructor is not called when a host-owned resource is destroyed as it's
630    /// assumed the host knows how to handle destroying its own resources.
631    ///
632    /// The `dtor` closure is provided the store state as the first argument
633    /// along with the representation of the resource that was just destroyed.
634    ///
635    /// [`Resource<U>`]: crate::component::Resource
636    ///
637    /// # Errors
638    ///
639    /// The provided `dtor` closure returns an error if something goes wrong
640    /// when a guest calls the `dtor` to drop a `Resource<T>` such as
641    /// a runtime trap or a runtime limit being exceeded.
642    pub fn resource(
643        &mut self,
644        name: &str,
645        ty: ResourceType,
646        dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static,
647    ) -> Result<()> {
648        let dtor = Arc::new(crate::func::HostFunc::wrap_inner(
649            &self.engine,
650            move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.as_context_mut(), param),
651        ));
652        self.insert(name, Definition::Resource(ty, dtor))?;
653        Ok(())
654    }
655
656    /// Identical to [`Self::resource`], except that it takes an async destructor.
657    #[cfg(feature = "async")]
658    pub fn resource_async<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()>
659    where
660        F: for<'a> Fn(
661                StoreContextMut<'a, T>,
662                u32,
663            ) -> Box<dyn Future<Output = Result<()>> + Send + 'a>
664            + Send
665            + Sync
666            + 'static,
667    {
668        assert!(
669            self.engine.config().async_support,
670            "cannot use `resource_async` without enabling async support in the config"
671        );
672        let dtor = Arc::new(crate::func::HostFunc::wrap_inner(
673            &self.engine,
674            move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| {
675                cx.as_context_mut()
676                    .block_on(|store| dtor(store, param).into())?
677            },
678        ));
679        self.insert(name, Definition::Resource(ty, dtor))?;
680        Ok(())
681    }
682
683    /// Defines a nested instance within this instance.
684    ///
685    /// This can be used to describe arbitrarily nested levels of instances
686    /// within a linker to satisfy nested instance exports of components.
687    pub fn instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>> {
688        self.as_mut().into_instance(name)
689    }
690
691    /// Same as [`LinkerInstance::instance`] except with different lifetime
692    /// parameters.
693    pub fn into_instance(mut self, name: &str) -> Result<Self> {
694        let name = self.insert(name, Definition::Instance(NameMap::default()))?;
695        self.map = match self.map.raw_get_mut(&name) {
696            Some(Definition::Instance(map)) => map,
697            _ => unreachable!(),
698        };
699        self.path.truncate(self.path_len);
700        self.path.push(name);
701        self.path_len += 1;
702        Ok(self)
703    }
704
705    fn insert(&mut self, name: &str, item: Definition) -> Result<usize> {
706        self.map
707            .insert(name, self.strings, self.allow_shadowing, item)
708    }
709
710    fn get(&self, name: &str) -> Option<&Definition> {
711        self.map.get(name, self.strings)
712    }
713}
714
715impl NameMapIntern for Strings {
716    type Key = usize;
717
718    fn intern(&mut self, string: &str) -> usize {
719        if let Some(idx) = self.string2idx.get(string) {
720            return *idx;
721        }
722        let string: Arc<str> = string.into();
723        let idx = self.strings.len();
724        self.strings.push(string.clone());
725        self.string2idx.insert(string, idx);
726        idx
727    }
728
729    fn lookup(&self, string: &str) -> Option<usize> {
730        self.string2idx.get(string).cloned()
731    }
732}