1 #[cfg(feature = "component-model-async")] 2 use crate::component::concurrent::Accessor; 3 use crate::component::func::HostFunc; 4 use crate::component::instance::RuntimeImport; 5 use crate::component::matching::{InstanceType, TypeChecker}; 6 use crate::component::types; 7 use crate::component::{ 8 Component, ComponentNamedList, Instance, InstancePre, Lift, Lower, ResourceType, Val, 9 }; 10 use crate::hash_map::HashMap; 11 use crate::prelude::*; 12 use crate::{AsContextMut, Engine, Module, StoreContextMut}; 13 use alloc::sync::Arc; 14 use core::marker; 15 #[cfg(feature = "component-model-async")] 16 use core::pin::Pin; 17 use wasmtime_environ::PrimaryMap; 18 use 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/[email protected]`, `a:b/[email protected]`, 40 /// and `a:b/[email protected]` 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/[email protected]` in a [`Linker`] but a component 45 /// imports `a:b/[email protected]` 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/[email protected]` and the host has provided `a:b/[email protected]` 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. 61 pub 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 70 impl<T: 'static> Clone for Linker<T> { clone(&self) -> 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)] 84 pub 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. 94 pub 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)] 105 pub(crate) enum Definition { 106 Instance(NameMap<usize, Definition>), 107 Func(Arc<HostFunc>), 108 Module(Module), 109 Resource(ResourceType, Arc<crate::func::HostFunc>), 110 } 111 112 impl<T: 'static> Linker<T> { 113 /// Creates a new linker for the [`Engine`] specified with no items defined 114 /// within it. new(engine: &Engine) -> Linker<T>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. engine(&self) -> &Engine127 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. allow_shadowing(&mut self, allow: bool) -> &mut Self135 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. root(&mut self) -> LinkerInstance<'_, T>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. instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>>159 pub fn instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>> { 160 self.root().into_instance(name) 161 } 162 typecheck<'a>(&'a self, component: &'a Component) -> Result<TypeChecker<'a>>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`]. substituted_component_type(&self, component: &Component) -> Result<types::Component>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. instantiate_pre(&self, component: &Component) -> Result<InstancePre<T>>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. instantiate( &self, mut store: impl AsContextMut<Data = T>, component: &Component, ) -> Result<Instance>274 pub fn instantiate( 275 &self, 276 mut store: impl AsContextMut<Data = T>, 277 component: &Component, 278 ) -> Result<Instance> { 279 let store = store.as_context_mut(); 280 store.0.validate_sync_call()?; 281 self.instantiate_pre(component)?.instantiate(store) 282 } 283 284 /// Instantiates the [`Component`] provided into the `store` specified. 285 /// 286 /// This is exactly like [`Linker::instantiate`] except for [asynchronous 287 /// execution](crate#async). 288 /// 289 /// # Errors 290 /// 291 /// Returns an error if this [`Linker`] doesn't define an import that 292 /// `component` requires or if it is of the wrong type. Additionally this 293 /// can return an error if something goes wrong during instantiation such as 294 /// a runtime trap or a runtime limit being exceeded. 295 #[cfg(feature = "async")] instantiate_async( &self, store: impl AsContextMut<Data = T>, component: &Component, ) -> Result<Instance> where T: Send,296 pub async fn instantiate_async( 297 &self, 298 store: impl AsContextMut<Data = T>, 299 component: &Component, 300 ) -> Result<Instance> 301 where 302 T: Send, 303 { 304 self.instantiate_pre(component)? 305 .instantiate_async(store) 306 .await 307 } 308 309 /// Implement any imports of the given [`Component`] with a function which traps. 310 /// 311 /// By default a [`Linker`] will error when unknown imports are encountered when instantiating a [`Component`]. 312 /// This changes this behavior from an instant error to a trap that will happen if the import is called. define_unknown_imports_as_traps(&mut self, component: &Component) -> Result<()>313 pub fn define_unknown_imports_as_traps(&mut self, component: &Component) -> Result<()> { 314 use wasmtime_environ::component::ComponentTypes; 315 use wasmtime_environ::component::TypeDef; 316 // Recursively stub out all imports of the component with a function that traps. 317 fn stub_item<T>( 318 linker: &mut LinkerInstance<T>, 319 item_name: &str, 320 item_def: &TypeDef, 321 parent_instance: Option<&str>, 322 types: &ComponentTypes, 323 ) -> Result<()> { 324 // Skip if the item isn't an instance and has already been defined in the linker. 325 if !matches!(item_def, TypeDef::ComponentInstance(_)) && linker.get(item_name).is_some() 326 { 327 return Ok(()); 328 } 329 330 match item_def { 331 TypeDef::ComponentFunc(_) => { 332 let fully_qualified_name = parent_instance 333 .map(|parent| format!("{parent}#{item_name}")) 334 .unwrap_or_else(|| item_name.to_owned()); 335 linker.func_new(&item_name, move |_, _, _, _| { 336 bail!("unknown import: `{fully_qualified_name}` has not been defined") 337 })?; 338 } 339 TypeDef::ComponentInstance(i) => { 340 let instance = &types[*i]; 341 let mut linker_instance = linker.instance(item_name)?; 342 for (export_name, export) in instance.exports.iter() { 343 stub_item( 344 &mut linker_instance, 345 export_name, 346 export, 347 Some(item_name), 348 types, 349 )?; 350 } 351 } 352 TypeDef::Resource(_) => { 353 let ty = crate::component::ResourceType::host::<()>(); 354 linker.resource(item_name, ty, |_, _| Ok(()))?; 355 } 356 TypeDef::Component(_) | TypeDef::Module(_) => { 357 bail!("unable to define {} imports as traps", item_def.desc()) 358 } 359 _ => {} 360 } 361 Ok(()) 362 } 363 364 for (_, (import_name, import_type)) in &component.env_component().import_types { 365 stub_item( 366 &mut self.root(), 367 import_name, 368 import_type, 369 None, 370 component.types(), 371 )?; 372 } 373 Ok(()) 374 } 375 } 376 377 impl<T: 'static> LinkerInstance<'_, T> { as_mut(&mut self) -> LinkerInstance<'_, T>378 fn as_mut(&mut self) -> LinkerInstance<'_, T> { 379 LinkerInstance { 380 engine: self.engine, 381 path: self.path, 382 path_len: self.path_len, 383 strings: self.strings, 384 map: self.map, 385 allow_shadowing: self.allow_shadowing, 386 _marker: self._marker, 387 } 388 } 389 390 /// Defines a new host-provided function into this [`LinkerInstance`]. 391 /// 392 /// This method is used to give host functions to wasm components. The 393 /// `func` provided will be callable from linked components with the type 394 /// signature dictated by `Params` and `Return`. The `Params` is a tuple of 395 /// types that will come from wasm and `Return` is a value coming from the 396 /// host going back to wasm. 397 /// 398 /// Additionally the `func` takes a 399 /// [`StoreContextMut`](crate::StoreContextMut) as its first parameter. 400 /// 401 /// Note that `func` must be an `Fn` and must also be `Send + Sync + 402 /// 'static`. Shared state within a func is typically accessed with the `T` 403 /// type parameter from [`Store<T>`](crate::Store) which is accessible 404 /// through the leading [`StoreContextMut<'_, T>`](crate::StoreContextMut) 405 /// argument which can be provided to the `func` given here. 406 /// 407 /// # Blocking / Async Behavior 408 /// 409 /// The host function `func` provided here is a blocking function from the 410 /// perspective of WebAssembly. WebAssembly, and Rust, will be blocked until 411 /// `func` completes. 412 /// 413 /// To define a function which is async on the host, but blocking to the 414 /// guest, see the [`func_wrap_async`] method. 415 /// 416 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async 417 // 418 // TODO: needs more words and examples func_wrap<F, Params, Return>(&mut self, name: &str, func: F) -> Result<()> where F: Fn(StoreContextMut<T>, Params) -> Result<Return> + Send + Sync + 'static, Params: ComponentNamedList + Lift + 'static, Return: ComponentNamedList + Lower + 'static,419 pub fn func_wrap<F, Params, Return>(&mut self, name: &str, func: F) -> Result<()> 420 where 421 F: Fn(StoreContextMut<T>, Params) -> Result<Return> + Send + Sync + 'static, 422 Params: ComponentNamedList + Lift + 'static, 423 Return: ComponentNamedList + Lower + 'static, 424 { 425 self.insert(name, Definition::Func(HostFunc::func_wrap(func)))?; 426 Ok(()) 427 } 428 429 /// Defines a new host-provided async function into this [`LinkerInstance`]. 430 /// 431 /// This function is similar to [`Self::func_wrap`] except it takes an async 432 /// host function instead of a blocking host function. The `F` function here 433 /// is intended to be: 434 /// 435 /// ```ignore 436 /// F: AsyncFn(StoreContextMut<'_, T>, Params) -> Result<Return> 437 /// ``` 438 /// 439 /// however the returned future must be `Send` which is not possible to 440 /// bound at this time. This will be switched to an async closure once Rust 441 /// supports it. 442 /// 443 /// # Blocking / Async Behavior 444 /// 445 /// The function defined which WebAssembly calls will still appear as 446 /// blocking from the perspective of WebAssembly itself. The host, however, 447 /// can perform asynchronous operations without blocking the thread 448 /// performing a call. 449 /// 450 /// When defining host functions with this function, WebAssembly is invoked 451 /// on a separate stack within a Wasmtime-managed fiber (through the 452 /// `call_async`-style of invocation). This means that if the future 453 /// returned by `F` is not immediately ready then the fiber will be 454 /// suspended to block WebAssembly but not the host. When the future 455 /// becomes ready again the fiber will be resumed to continue execution 456 /// within WebAssembly. 457 /// 458 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async 459 #[cfg(feature = "async")] func_wrap_async<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()> where F: Fn( StoreContextMut<'_, T>, Params, ) -> Box<dyn Future<Output = Result<Return>> + Send + '_> + Send + Sync + 'static, Params: ComponentNamedList + Lift + 'static, Return: ComponentNamedList + Lower + 'static,460 pub fn func_wrap_async<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()> 461 where 462 F: Fn( 463 StoreContextMut<'_, T>, 464 Params, 465 ) -> Box<dyn Future<Output = Result<Return>> + Send + '_> 466 + Send 467 + Sync 468 + 'static, 469 Params: ComponentNamedList + Lift + 'static, 470 Return: ComponentNamedList + Lower + 'static, 471 { 472 self.insert(name, Definition::Func(HostFunc::func_wrap_async(f)))?; 473 Ok(()) 474 } 475 476 /// Defines a new host-provided async function into this [`LinkerInstance`]. 477 /// 478 /// This function defines a host function available to call from 479 /// WebAssembly. WebAssembly may additionally make multiple invocations of 480 /// this function concurrently all at the same time. This function requires 481 /// the [`Config::wasm_component_model_async`] feature to be enabled. 482 /// 483 /// The function `f` provided will be invoked when called by WebAssembly. 484 /// WebAssembly components may then call `f` multiple times while previous 485 /// invocations of `f` are already running. Additionally while `f` is 486 /// running other host functions may be invoked. 487 /// 488 /// The `F` function here is intended to be: 489 /// 490 /// ```ignore 491 /// F: AsyncFn(&Accessor<T>, Params) -> Result<Return> 492 /// ``` 493 /// 494 /// however the returned future must be `Send` which is not possible to 495 /// bound at this time. This will be switched to an async closure once Rust 496 /// supports it. 497 /// 498 /// The closure `f` is provided an [`Accessor`] which can be used to acquire 499 /// temporary, blocking, access to a [`StoreContextMut`] (through 500 /// [`Access`](crate::component::Access]). This models how a store is not 501 /// available to `f` across `await` points but it is temporarily available 502 /// while actively being polled. 503 /// 504 /// # Blocking / Async Behavior 505 /// 506 /// Unlike [`Self::func_wrap`] and [`Self::func_wrap_async`] this function 507 /// is asynchronous even from the perspective of guest WebAssembly. This 508 /// means that if `f` is not immediately resolved then the call from 509 /// WebAssembly will still return immediately (assuming it was lowered with 510 /// `async`). The closure `f` should not block the current thread and 511 /// should only perform blocking via `async` meaning that `f` won't block 512 /// either WebAssembly nor the host. 513 /// 514 /// Note that WebAssembly components can lower host functions both with and 515 /// without `async`. That means that even if a host function is defined in 516 /// the "concurrent" mode here a guest may still lower it synchronously. In 517 /// this situation Wasmtime will manage blocking the guest while the closure 518 /// `f` provided here completes. If a guest lowers this function with 519 /// `async`, though, then no blocking will happen. 520 /// 521 /// [`Config::wasm_component_model_async`]: crate::Config::wasm_component_model_async 522 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async 523 #[cfg(feature = "component-model-async")] func_wrap_concurrent<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()> where T: 'static, F: Fn(&Accessor<T>, Params) -> Pin<Box<dyn Future<Output = Result<Return>> + Send + '_>> + Send + Sync + 'static, Params: ComponentNamedList + Lift + 'static, Return: ComponentNamedList + Lower + 'static,524 pub fn func_wrap_concurrent<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()> 525 where 526 T: 'static, 527 F: Fn(&Accessor<T>, Params) -> Pin<Box<dyn Future<Output = Result<Return>> + Send + '_>> 528 + Send 529 + Sync 530 + 'static, 531 Params: ComponentNamedList + Lift + 'static, 532 Return: ComponentNamedList + Lower + 'static, 533 { 534 if !self.engine.tunables().concurrency_support { 535 bail!("concurrent host functions require `Config::concurrency_support`"); 536 } 537 self.insert(name, Definition::Func(HostFunc::func_wrap_concurrent(f)))?; 538 Ok(()) 539 } 540 541 /// Define a new host-provided function using dynamically typed values. 542 /// 543 /// The `name` provided is the name of the function to define and the 544 /// `func` provided is the host-defined closure to invoke when this 545 /// function is called. 546 /// 547 /// This function is the "dynamic" version of defining a host function as 548 /// compared to [`LinkerInstance::func_wrap`]. With 549 /// [`LinkerInstance::func_wrap`] a function's type is statically known but 550 /// with this method the `func` argument's type isn't known ahead of time. 551 /// That means that `func` can be by imported component so long as it's 552 /// imported as a matching name. 553 /// 554 /// Type information will be available at execution time, however. For 555 /// example when `func` is invoked the second argument, a `&[Val]` list, 556 /// contains [`Val`] entries that say what type they are. Additionally the 557 /// third argument, `&mut [Val]`, is the expected number of results. Note 558 /// that the expected types of the results cannot be learned during the 559 /// execution of `func`. Learning that would require runtime introspection 560 /// of a component. 561 /// 562 /// Return values, stored in the third argument of `&mut [Val]`, are 563 /// type-checked at runtime to ensure that they have the appropriate type. 564 /// A trap will be raised if they do not have the right type. 565 /// 566 /// # Examples 567 /// 568 /// ``` 569 /// use wasmtime::{Store, Engine}; 570 /// use wasmtime::component::{Component, Linker, Val}; 571 /// 572 /// # fn main() -> wasmtime::Result<()> { 573 /// let engine = Engine::default(); 574 /// let component = Component::new( 575 /// &engine, 576 /// r#" 577 /// (component 578 /// (import "thunk" (func $thunk)) 579 /// (import "is-even" (func $is-even (param "x" u32) (result bool))) 580 /// 581 /// (core module $m 582 /// (import "" "thunk" (func $thunk)) 583 /// (import "" "is-even" (func $is-even (param i32) (result i32))) 584 /// 585 /// (func (export "run") 586 /// call $thunk 587 /// 588 /// (call $is-even (i32.const 1)) 589 /// if unreachable end 590 /// 591 /// (call $is-even (i32.const 2)) 592 /// i32.eqz 593 /// if unreachable end 594 /// ) 595 /// ) 596 /// (core func $thunk (canon lower (func $thunk))) 597 /// (core func $is-even (canon lower (func $is-even))) 598 /// (core instance $i (instantiate $m 599 /// (with "" (instance 600 /// (export "thunk" (func $thunk)) 601 /// (export "is-even" (func $is-even)) 602 /// )) 603 /// )) 604 /// 605 /// (func (export "run") (canon lift (core func $i "run"))) 606 /// ) 607 /// "#, 608 /// )?; 609 /// 610 /// let mut linker = Linker::<()>::new(&engine); 611 /// 612 /// // Sample function that takes no arguments. 613 /// linker.root().func_new("thunk", |_store, _ty, params, results| { 614 /// assert!(params.is_empty()); 615 /// assert!(results.is_empty()); 616 /// println!("Look ma, host hands!"); 617 /// Ok(()) 618 /// })?; 619 /// 620 /// // This function takes one argument and returns one result. 621 /// linker.root().func_new("is-even", |_store, _ty, params, results| { 622 /// assert_eq!(params.len(), 1); 623 /// let param = match params[0] { 624 /// Val::U32(n) => n, 625 /// _ => panic!("unexpected type"), 626 /// }; 627 /// 628 /// assert_eq!(results.len(), 1); 629 /// results[0] = Val::Bool(param % 2 == 0); 630 /// Ok(()) 631 /// })?; 632 /// 633 /// let mut store = Store::new(&engine, ()); 634 /// let instance = linker.instantiate(&mut store, &component)?; 635 /// let run = instance.get_typed_func::<(), ()>(&mut store, "run")?; 636 /// run.call(&mut store, ())?; 637 /// # Ok(()) 638 /// # } 639 /// ``` func_new( &mut self, name: &str, func: impl Fn(StoreContextMut<'_, T>, types::ComponentFunc, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static, ) -> Result<()>640 pub fn func_new( 641 &mut self, 642 name: &str, 643 func: impl Fn(StoreContextMut<'_, T>, types::ComponentFunc, &[Val], &mut [Val]) -> Result<()> 644 + Send 645 + Sync 646 + 'static, 647 ) -> Result<()> { 648 self.insert(name, Definition::Func(HostFunc::func_new(func)))?; 649 Ok(()) 650 } 651 652 /// Define a new host-provided async function using dynamic types. 653 /// 654 /// As [`Self::func_wrap_async`] is a dual of [`Self::func_wrap`], this 655 /// function is the dual of [`Self::func_new`]. 656 /// 657 /// For documentation on blocking behavior see [`Self::func_wrap_async`]. 658 #[cfg(feature = "async")] func_new_async<F>(&mut self, name: &str, func: F) -> Result<()> where F: for<'a> Fn( StoreContextMut<'a, T>, types::ComponentFunc, &'a [Val], &'a mut [Val], ) -> Box<dyn Future<Output = Result<()>> + Send + 'a> + Send + Sync + 'static,659 pub fn func_new_async<F>(&mut self, name: &str, func: F) -> Result<()> 660 where 661 F: for<'a> Fn( 662 StoreContextMut<'a, T>, 663 types::ComponentFunc, 664 &'a [Val], 665 &'a mut [Val], 666 ) -> Box<dyn Future<Output = Result<()>> + Send + 'a> 667 + Send 668 + Sync 669 + 'static, 670 { 671 self.insert(name, Definition::Func(HostFunc::func_new_async(func)))?; 672 Ok(()) 673 } 674 675 /// Define a new host-provided async function using dynamic types. 676 /// 677 /// As [`Self::func_wrap_concurrent`] is a dual of [`Self::func_wrap`], this 678 /// function is the dual of [`Self::func_new`]. 679 /// 680 /// For documentation on async/blocking behavior see 681 /// [`Self::func_wrap_concurrent`]. 682 #[cfg(feature = "component-model-async")] func_new_concurrent<F>(&mut self, name: &str, f: F) -> Result<()> where T: 'static, F: for<'a> Fn( &'a Accessor<T>, types::ComponentFunc, &'a [Val], &'a mut [Val], ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>> + Send + Sync + 'static,683 pub fn func_new_concurrent<F>(&mut self, name: &str, f: F) -> Result<()> 684 where 685 T: 'static, 686 F: for<'a> Fn( 687 &'a Accessor<T>, 688 types::ComponentFunc, 689 &'a [Val], 690 &'a mut [Val], 691 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>> 692 + Send 693 + Sync 694 + 'static, 695 { 696 if !self.engine.tunables().concurrency_support { 697 bail!("concurrent host functions require `Config::concurrency_support`"); 698 } 699 self.insert(name, Definition::Func(HostFunc::func_new_concurrent(f)))?; 700 Ok(()) 701 } 702 703 /// Defines a [`Module`] within this instance. 704 /// 705 /// This can be used to provide a core wasm [`Module`] as an import to a 706 /// component. The [`Module`] provided is saved within the linker for the 707 /// specified `name` in this instance. module(&mut self, name: &str, module: &Module) -> Result<()>708 pub fn module(&mut self, name: &str, module: &Module) -> Result<()> { 709 self.insert(name, Definition::Module(module.clone()))?; 710 Ok(()) 711 } 712 713 /// Defines a new resource of a given [`ResourceType`] in this linker. 714 /// 715 /// This function is used to specify resources defined in the host. 716 /// 717 /// The `name` argument is the name to define the resource within this 718 /// linker. 719 /// 720 /// The `dtor` provided is a destructor that will get invoked when an owned 721 /// version of this resource is destroyed from the guest. Note that this 722 /// destructor is not called when a host-owned resource is destroyed as it's 723 /// assumed the host knows how to handle destroying its own resources. 724 /// 725 /// The `dtor` closure is provided the store state as the first argument 726 /// along with the representation of the resource that was just destroyed. 727 /// 728 /// [`Resource<U>`]: crate::component::Resource 729 /// 730 /// # Errors 731 /// 732 /// The provided `dtor` closure returns an error if something goes wrong 733 /// when a guest calls the `dtor` to drop a `Resource<T>` such as 734 /// a runtime trap or a runtime limit being exceeded. resource( &mut self, name: &str, ty: ResourceType, dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static, ) -> Result<()>735 pub fn resource( 736 &mut self, 737 name: &str, 738 ty: ResourceType, 739 dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static, 740 ) -> Result<()> { 741 let dtor = Arc::new(crate::func::HostFunc::wrap( 742 &self.engine, 743 move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.as_context_mut(), param), 744 )?); 745 self.insert(name, Definition::Resource(ty, dtor))?; 746 Ok(()) 747 } 748 749 /// Identical to [`Self::resource`], except that it takes an async destructor. 750 #[cfg(feature = "async")] resource_async<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()> where T: Send, F: Fn(StoreContextMut<'_, T>, u32) -> Box<dyn Future<Output = Result<()>> + Send + '_> + Send + Sync + 'static,751 pub fn resource_async<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()> 752 where 753 T: Send, 754 F: Fn(StoreContextMut<'_, T>, u32) -> Box<dyn Future<Output = Result<()>> + Send + '_> 755 + Send 756 + Sync 757 + 'static, 758 { 759 let dtor = Arc::new(crate::func::HostFunc::wrap_async( 760 &self.engine, 761 move |cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.into(), param), 762 )?); 763 self.insert(name, Definition::Resource(ty, dtor))?; 764 Ok(()) 765 } 766 767 /// Identical to [`Self::resource`], except that it takes a concurrent destructor. 768 #[cfg(feature = "component-model-async")] resource_concurrent<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()> where T: Send + 'static, F: Fn(&Accessor<T>, u32) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>> + Send + Sync + 'static,769 pub fn resource_concurrent<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()> 770 where 771 T: Send + 'static, 772 F: Fn(&Accessor<T>, u32) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>> 773 + Send 774 + Sync 775 + 'static, 776 { 777 if !self.engine.tunables().concurrency_support { 778 bail!("concurrent host functions require `Config::concurrency_support`"); 779 } 780 // TODO: This isn't really concurrent -- it requires exclusive access to 781 // the store for the duration of the call, preventing guest code from 782 // running until it completes. We should make it concurrent and clean 783 // up the implementation to avoid using e.g. `Accessor::new` and 784 // `tls::set` directly. 785 let dtor = Arc::new(dtor); 786 let dtor = Arc::new(crate::func::HostFunc::wrap_async( 787 &self.engine, 788 move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| { 789 let dtor = dtor.clone(); 790 Box::new(async move { 791 let mut store = cx.as_context_mut(); 792 let accessor = 793 &Accessor::new(crate::store::StoreToken::new(store.as_context_mut())); 794 let mut future = std::pin::pin!(dtor(accessor, param)); 795 std::future::poll_fn(|cx| { 796 crate::component::concurrent::tls::set(store.0, || future.as_mut().poll(cx)) 797 }) 798 .await 799 }) 800 }, 801 )?); 802 self.insert(name, Definition::Resource(ty, dtor))?; 803 Ok(()) 804 } 805 806 /// Defines a nested instance within this instance. 807 /// 808 /// This can be used to describe arbitrarily nested levels of instances 809 /// within a linker to satisfy nested instance exports of components. instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>>810 pub fn instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>> { 811 self.as_mut().into_instance(name) 812 } 813 814 /// Same as [`LinkerInstance::instance`] except with different lifetime 815 /// parameters. into_instance(mut self, name: &str) -> Result<Self>816 pub fn into_instance(mut self, name: &str) -> Result<Self> { 817 let name = self.insert(name, Definition::Instance(NameMap::default()))?; 818 self.map = match self.map.raw_get_mut(&name) { 819 Some(Definition::Instance(map)) => map, 820 _ => unreachable!(), 821 }; 822 self.path.truncate(self.path_len); 823 self.path.push(name); 824 self.path_len += 1; 825 Ok(self) 826 } 827 insert(&mut self, name: &str, item: Definition) -> Result<usize>828 fn insert(&mut self, name: &str, item: Definition) -> Result<usize> { 829 self.map 830 .insert(name, self.strings, self.allow_shadowing, item) 831 } 832 get(&self, name: &str) -> Option<&Definition>833 fn get(&self, name: &str) -> Option<&Definition> { 834 self.map.get(name, self.strings) 835 } 836 } 837 838 impl NameMapIntern for Strings { 839 type Key = usize; 840 intern(&mut self, string: &str) -> usize841 fn intern(&mut self, string: &str) -> usize { 842 if let Some(idx) = self.string2idx.get(string) { 843 return *idx; 844 } 845 let string: Arc<str> = string.into(); 846 let idx = self.strings.len(); 847 self.strings.push(string.clone()); 848 self.string2idx.insert(string, idx); 849 idx 850 } 851 lookup(&self, string: &str) -> Option<usize>852 fn lookup(&self, string: &str) -> Option<usize> { 853 self.string2idx.get(string).cloned() 854 } 855 } 856