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