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}