wiggle::wasmtime_crate

Struct Linker

pub struct Linker<T> { /* private fields */ }
Expand description

Structure used to link wasm modules/instances together.

This structure is used to assist in instantiating a Module. A Linker is a way of performing name resolution to make instantiating a module easier than specifying positional imports to Instance::new. Linker is a name-based resolver where names are dynamically defined and then used to instantiate a Module.

An important method is Linker::instantiate which takes a module to instantiate into the provided store. This method will automatically select all the right imports for the Module to be instantiated, and will otherwise return an error if an import isn’t satisfied.

§Name Resolution

As mentioned previously, Linker is a form of name resolver. It will be using the string-based names of imports on a module to attempt to select a matching item to hook up to it. This name resolution has two-levels of namespaces, a module level and a name level. Each item is defined within a module and then has its own name. This basically follows the wasm standard for modularization.

Names in a Linker cannot be defined twice, but allowing duplicates by shadowing the previous definition can be controlled with the Linker::allow_shadowing method.

§Commands and Reactors

The Linker type provides conveniences for working with WASI Commands and Reactors through the Linker::module method. This will automatically handle instantiation and calling _start and such as appropriate depending on the inferred type of module.

§Type parameter T

It’s worth pointing out that the type parameter T on Linker<T> does not represent that T is stored within a Linker. Rather the T is used to ensure that linker-defined functions and stores instantiated into all use the same matching T as host state.

§Multiple Stores

The Linker type is designed to be compatible, in some scenarios, with instantiation in multiple Stores. Specifically host-defined functions created in Linker with Linker::func_new, Linker::func_wrap, and their async versions are compatible to instantiate into any Store. This enables programs which want to instantiate lots of modules to create one Linker value at program start up and use that continuously for each Store created over the lifetime of the program.

Note that once Store-owned items, such as Global, are defined within a Linker then it is no longer compatible with any Store. At that point only the Store that owns the Global can be used to instantiate modules.

§Multiple Engines

The Linker type is not compatible with usage between multiple Engine values. An Engine is provided when a Linker is created and only stores and items which originate from that Engine can be used with this Linker. If more than one Engine is used with a Linker then that may cause a panic at runtime, similar to how if a Func is used with the wrong Store that can also panic at runtime.

Implementations§

§

impl<T> Linker<T>

pub fn new(engine: &Engine) -> Linker<T>

Creates a new Linker.

The linker will define functions within the context of the engine provided and can only instantiate modules for a Store that is also defined within the same Engine. Usage of stores with different Engines may cause a panic when used with this Linker.

pub fn engine(&self) -> &Engine

Returns the Engine this is connected to.

pub fn allow_shadowing(&mut self, allow: bool) -> &mut Linker<T>

Configures whether this Linker will shadow previous duplicate definitions of the same signature.

By default a Linker will disallow duplicate definitions of the same signature. This method, however, can be used to instead allow duplicates and have the latest definition take precedence when linking modules.

§Examples
let mut linker = Linker::<()>::new(&engine);
linker.func_wrap("", "", || {})?;

// by default, duplicates are disallowed
assert!(linker.func_wrap("", "", || {}).is_err());

// but shadowing can be configured to be allowed as well
linker.allow_shadowing(true);
linker.func_wrap("", "", || {})?;

pub fn allow_unknown_exports(&mut self, allow: bool) -> &mut Linker<T>

Configures whether this Linker will allow unknown exports from command modules.

By default a Linker will error when unknown exports are encountered in a command module while using Linker::module.

This method can be used to allow unknown exports from command modules.

§Examples
let mut linker = Linker::new(&engine);
linker.allow_unknown_exports(true);
linker.module(&mut store, "mod", &module)?;

pub fn define_unknown_imports_as_traps( &mut self, module: &Module, ) -> Result<(), Error>

Implement any imports of the given Module with a function which traps.

By default a Linker will error when unknown imports are encountered in a command module while using Linker::module.

This method can be used to allow unknown imports from command modules.

§Examples
let mut linker = Linker::new(&engine);
linker.define_unknown_imports_as_traps(&module)?;
linker.instantiate(&mut store, &module)?;

pub fn define_unknown_imports_as_default_values( &mut self, module: &Module, ) -> Result<(), Error>

Implement any function imports of the Module with a function that ignores its arguments and returns default values.

Default values are either zero or null, depending on the value type.

This method can be used to allow unknown imports from command modules.

§Example
let mut linker = Linker::new(&engine);
linker.define_unknown_imports_as_default_values(&module)?;
linker.instantiate(&mut store, &module)?;

pub fn define( &mut self, store: impl AsContext<Data = T>, module: &str, name: &str, item: impl Into<Extern>, ) -> Result<&mut Linker<T>, Error>

Defines a new item in this Linker.

This method will add a new definition, by name, to this instance of Linker. The module and name provided are what to name the item.

§Errors

Returns an error if the module and name already identify an item of the same type as the item provided and if shadowing is disallowed. For more information see the documentation on Linker.

§Examples
let mut linker = Linker::new(&engine);
let ty = GlobalType::new(ValType::I32, Mutability::Const);
let global = Global::new(&mut store, ty, Val::I32(0x1234))?;
linker.define(&store, "host", "offset", global)?;

let wat = r#"
    (module
        (import "host" "offset" (global i32))
        (memory 1)
        (data (global.get 0) "foo")
    )
"#;
let module = Module::new(&engine, wat)?;
linker.instantiate(&mut store, &module)?;

pub fn define_name( &mut self, store: impl AsContext<Data = T>, name: &str, item: impl Into<Extern>, ) -> Result<&mut Linker<T>, Error>

Same as Linker::define, except only the name of the import is provided, not a module name as well.

This is only relevant when working with the module linking proposal where one-level names are allowed (in addition to two-level names). Otherwise this method need not be used.

pub fn func_new( &mut self, module: &str, name: &str, ty: FuncType, func: impl Fn(Caller<'_, T>, &[Val], &mut [Val]) -> Result<(), Error> + Send + Sync + 'static, ) -> Result<&mut Linker<T>, Error>

Creates a Func::new-style function named in this linker.

For more information see Linker::func_wrap.

§Panics

Panics if the given function type is not associated with the same engine as this linker.

pub unsafe fn func_new_unchecked( &mut self, module: &str, name: &str, ty: FuncType, func: impl Fn(Caller<'_, T>, &mut [ValRaw]) -> Result<(), Error> + Send + Sync + 'static, ) -> Result<&mut Linker<T>, Error>

Creates a Func::new_unchecked-style function named in this linker.

For more information see Linker::func_wrap.

§Panics

Panics if the given function type is not associated with the same engine as this linker.

pub fn func_new_async<F>( &mut self, module: &str, name: &str, ty: FuncType, func: F, ) -> Result<&mut Linker<T>, Error>
where F: for<'a> Fn(Caller<'a, T>, &'a [Val], &'a mut [Val]) -> Box<dyn Future<Output = Result<(), Error>> + Send + 'a> + Send + Sync + 'static,

Creates a Func::new_async-style function named in this linker.

For more information see Linker::func_wrap.

§Panics

This method panics in the following situations:

  • This linker is not associated with an async config.

  • If the given function type is not associated with the same engine as this linker.

pub fn func_wrap<Params, Args>( &mut self, module: &str, name: &str, func: impl IntoFunc<T, Params, Args>, ) -> Result<&mut Linker<T>, Error>

Define a host function within this linker.

For information about how the host function operates, see Func::wrap. That includes information about translating Rust types to WebAssembly native types.

This method creates a host-provided function in this linker under the provided name. This method is distinct in its capability to create a Store-independent function. This means that the function defined here can be used to instantiate instances in multiple different stores, or in other words the function can be loaded into different stores.

Note that the capability mentioned here applies to all other host-function-defining-methods on Linker as well. All of them can be used to create instances of Func within multiple stores. In a multithreaded program, for example, this means that the host functions could be called concurrently if different stores are executing on different threads.

§Errors

Returns an error if the module and name already identify an item of the same type as the item provided and if shadowing is disallowed. For more information see the documentation on Linker.

§Examples
let mut linker = Linker::new(&engine);
linker.func_wrap("host", "double", |x: i32| x * 2)?;
linker.func_wrap("host", "log_i32", |x: i32| println!("{}", x))?;
linker.func_wrap("host", "log_str", |caller: Caller<'_, ()>, ptr: i32, len: i32| {
    // ...
})?;

let wat = r#"
    (module
        (import "host" "double" (func (param i32) (result i32)))
        (import "host" "log_i32" (func (param i32)))
        (import "host" "log_str" (func (param i32 i32)))
    )
"#;
let module = Module::new(&engine, wat)?;

// instantiate in multiple different stores
for _ in 0..10 {
    let mut store = Store::new(&engine, ());
    linker.instantiate(&mut store, &module)?;
}

pub fn func_wrap_async<F, Params, Args>( &mut self, module: &str, name: &str, func: F, ) -> Result<&mut Linker<T>, Error>
where Params: WasmTyList, Args: WasmRet, F: for<'a> Fn(Caller<'a, T>, Params) -> Box<dyn Future<Output = Args> + Send + 'a> + Send + Sync + 'static,

Asynchronous analog of Linker::func_wrap.

pub fn instance( &mut self, store: impl AsContextMut<Data = T>, module_name: &str, instance: Instance, ) -> Result<&mut Linker<T>, Error>

Convenience wrapper to define an entire Instance in this linker.

This function is a convenience wrapper around Linker::define which will define all exports on instance into this linker. The module name for each export is module_name, and the name for each export is the name in the instance itself.

Note that when this API is used the Linker is no longer compatible with multi-Store instantiation because the items defined within this store will belong to the store provided, and only the store provided.

§Errors

Returns an error if the any item is redefined twice in this linker (for example the same module_name was already defined) and shadowing is disallowed, or if instance comes from a different Store than this Linker originally was created with.

§Panics

Panics if instance does not belong to store.

§Examples
let mut linker = Linker::new(&engine);

// Instantiate a small instance...
let wat = r#"(module (func (export "run") ))"#;
let module = Module::new(&engine, wat)?;
let instance = linker.instantiate(&mut store, &module)?;

// ... and inform the linker that the name of this instance is
// `instance1`. This defines the `instance1::run` name for our next
// module to use.
linker.instance(&mut store, "instance1", instance)?;

let wat = r#"
    (module
        (import "instance1" "run" (func $instance1_run))
        (func (export "run")
            call $instance1_run
        )
    )
"#;
let module = Module::new(&engine, wat)?;
let instance = linker.instantiate(&mut store, &module)?;

pub fn module( &mut self, store: impl AsContextMut<Data = T>, module_name: &str, module: &Module, ) -> Result<&mut Linker<T>, Error>
where T: 'static,

Define automatic instantiations of a Module in this linker.

This automatically handles Commands and Reactors instantiation and initialization.

Exported functions of a Command module may be called directly, however instead of having a single instance which is reused for each call, each call creates a new instance, which lives for the duration of the call. The imports of the Command are resolved once, and reused for each instantiation, so all dependencies need to be present at the time when Linker::module is called.

For Reactors, a single instance is created, and an initialization function is called, and then its exports may be called.

Ordinary modules which don’t declare themselves to be either Commands or Reactors are treated as Reactors without any initialization calls.

§Errors

Returns an error if the any item is redefined twice in this linker (for example the same module_name was already defined) and shadowing is disallowed, if instance comes from a different Store than this Linker originally was created with, or if a Reactor initialization function traps.

§Panics

Panics if any item used to instantiate the provided Module is not owned by store, or if the store provided comes from a different Engine than this Linker.

§Examples
let mut linker = Linker::new(&engine);

// Instantiate a small instance and inform the linker that the name of
// this instance is `instance1`. This defines the `instance1::run` name
// for our next module to use.
let wat = r#"(module (func (export "run") ))"#;
let module = Module::new(&engine, wat)?;
linker.module(&mut store, "instance1", &module)?;

let wat = r#"
    (module
        (import "instance1" "run" (func $instance1_run))
        (func (export "run")
            call $instance1_run
        )
    )
"#;
let module = Module::new(&engine, wat)?;
let instance = linker.instantiate(&mut store, &module)?;

For a Command, a new instance is created for each call.

let mut linker = Linker::new(&engine);

// Create a Command that attempts to count the number of times it is run, but is
// foiled by each call getting a new instance.
let wat = r#"
    (module
        (global $counter (mut i32) (i32.const 0))
        (func (export "_start")
            (global.set $counter (i32.add (global.get $counter) (i32.const 1)))
        )
        (func (export "read_counter") (result i32)
            (global.get $counter)
        )
    )
"#;
let module = Module::new(&engine, wat)?;
linker.module(&mut store, "commander", &module)?;
let run = linker.get_default(&mut store, "")?
    .typed::<(), ()>(&store)?
    .clone();
run.call(&mut store, ())?;
run.call(&mut store, ())?;
run.call(&mut store, ())?;

let wat = r#"
    (module
        (import "commander" "_start" (func $commander_start))
        (import "commander" "read_counter" (func $commander_read_counter (result i32)))
        (func (export "run") (result i32)
            call $commander_start
            call $commander_start
            call $commander_start
            call $commander_read_counter
        )
    )
"#;
let module = Module::new(&engine, wat)?;
linker.module(&mut store, "", &module)?;
let run = linker.get(&mut store, "", "run").unwrap().into_func().unwrap();
let count = run.typed::<(), i32>(&store)?.call(&mut store, ())?;
assert_eq!(count, 0, "a Command should get a fresh instance on each invocation");

pub async fn module_async( &mut self, store: impl AsContextMut<Data = T>, module_name: &str, module: &Module, ) -> Result<&mut Linker<T>, Error>
where T: Send + 'static,

Define automatic instantiations of a Module in this linker.

This is the same as Linker::module, except for async Stores.

pub fn alias( &mut self, module: &str, name: &str, as_module: &str, as_name: &str, ) -> Result<&mut Linker<T>, Error>

Aliases one item’s name as another.

This method will alias an item with the specified module and name under a new name of as_module and as_name.

§Errors

Returns an error if any shadowing violations happen while defining new items, or if the original item wasn’t defined.

pub fn alias_module( &mut self, module: &str, as_module: &str, ) -> Result<(), Error>

Aliases one module’s name as another.

This method will alias all currently defined under module to also be defined under the name as_module too.

§Errors

Returns an error if any shadowing violations happen while defining new items.

pub fn instantiate( &self, store: impl AsContextMut<Data = T>, module: &Module, ) -> Result<Instance, Error>

Attempts to instantiate the module provided.

This method will attempt to assemble a list of imports that correspond to the imports required by the Module provided. This list of imports is then passed to Instance::new to continue the instantiation process.

Each import of module will be looked up in this Linker and must have previously been defined. If it was previously defined with an incorrect signature or if it was not previously defined then an error will be returned because the import can not be satisfied.

Per the WebAssembly spec, instantiation includes running the module’s start function, if it has one (not to be confused with the _start function, which is not run).

§Errors

This method can fail because an import may not be found, or because instantiation itself may fail. For information on instantiation failures see Instance::new. If an import is not found, the error may be downcast to an UnknownImportError.

§Panics

Panics if any item used to instantiate module is not owned by store. Additionally this will panic if the Engine that the store belongs to is different than this Linker.

§Examples
let mut linker = Linker::new(&engine);
linker.func_wrap("host", "double", |x: i32| x * 2)?;

let wat = r#"
    (module
        (import "host" "double" (func (param i32) (result i32)))
    )
"#;
let module = Module::new(&engine, wat)?;
linker.instantiate(&mut store, &module)?;

pub async fn instantiate_async( &self, store: impl AsContextMut<Data = T>, module: &Module, ) -> Result<Instance, Error>
where T: Send,

Attempts to instantiate the module provided. This is the same as Linker::instantiate, except for async Stores.

pub fn instantiate_pre(&self, module: &Module) -> Result<InstancePre<T>, Error>

Performs all checks necessary for instantiating module with this linker, except that instantiation doesn’t actually finish.

This method is used for front-loading type-checking information as well as collecting the imports to use to instantiate a module with. The returned InstancePre represents a ready-to-be-instantiated module, which can also be instantiated multiple times if desired.

§Errors

Returns an error which may be downcast to an UnknownImportError if the module has any unresolvable imports.

§Examples
let mut linker = Linker::new(&engine);
linker.func_wrap("host", "double", |x: i32| x * 2)?;

let wat = r#"
    (module
        (import "host" "double" (func (param i32) (result i32)))
    )
"#;
let module = Module::new(&engine, wat)?;
let instance_pre = linker.instantiate_pre(&module)?;

// Finish instantiation after the type-checking has all completed...
let instance = instance_pre.instantiate(&mut store)?;

// ... and we can even continue to keep instantiating if desired!
instance_pre.instantiate(&mut store)?;
instance_pre.instantiate(&mut store)?;

// Note that functions defined in a linker with `func_wrap` and similar
// constructors are not owned by any particular `Store`, so we can also
// instantiate our `instance_pre` in other stores because no imports
// belong to the original store.
let mut new_store = Store::new(&engine, ());
instance_pre.instantiate(&mut new_store)?;

pub fn iter<'a, 'p>( &'a self, store: impl AsContextMut<Data = T> + 'p, ) -> impl Iterator<Item = (&'a str, &'a str, Extern)> + 'p
where 'a: 'p,

Returns an iterator over all items defined in this Linker, in arbitrary order.

The iterator returned will yield 3-tuples where the first two elements are the module name and item name for the external item, and the third item is the item itself that is defined.

Note that multiple Extern items may be defined for the same module/name pair.

§Panics

This function will panic if the store provided does not come from the same Engine that this linker was created with.

pub fn get( &self, store: impl AsContextMut<Data = T>, module: &str, name: &str, ) -> Option<Extern>

Looks up a previously defined value in this Linker, identified by the names provided.

Returns None if this name was not previously defined in this Linker.

§Panics

This function will panic if the store provided does not come from the same Engine that this linker was created with.

pub fn get_by_import( &self, store: impl AsContextMut<Data = T>, import: &ImportType<'_>, ) -> Option<Extern>

Looks up a value in this Linker which matches the import type provided.

Returns None if no match was found.

§Panics

This function will panic if the store provided does not come from the same Engine that this linker was created with.

pub fn get_default( &self, store: impl AsContextMut<Data = T>, module: &str, ) -> Result<Func, Error>

Returns the “default export” of a module.

An export with an empty string is considered to be a “default export”. “_start” is also recognized for compatibility.

§Panics

Panics if the default function found is not owned by store. This function will also panic if the store provided does not come from the same Engine that this linker was created with.

Trait Implementations§

§

impl<T> Clone for Linker<T>

§

fn clone(&self) -> Linker<T>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
§

impl<T> Default for Linker<T>

§

fn default() -> Linker<T>

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<T> Freeze for Linker<T>

§

impl<T> !RefUnwindSafe for Linker<T>

§

impl<T> Send for Linker<T>

§

impl<T> Sync for Linker<T>

§

impl<T> Unpin for Linker<T>

§

impl<T> !UnwindSafe for Linker<T>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Pointee for T

source§

type Pointer = u32

source§

fn debug( pointer: <T as Pointee>::Pointer, f: &mut Formatter<'_>, ) -> Result<(), Error>

source§

impl<T> Same for T

source§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

source§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more