pub struct Linker<T> {/* private fields */ }
runtime
only.Expand description
Structure used to link wasm modules/instances together.
This structure is used to assist in instantiating aModule
. ALinker
is a way of performing name resolution to make instantiating a module easierthan specifying positional imports toInstance::new
.Linker
is aname-based resolver where names are dynamically defined and then used toinstantiate aModule
.
An important method isLinker::instantiate
which takes a module toinstantiate into the provided store. This method will automatically selectall the right imports for theModule
to be instantiated, and willotherwise return an error if an import isn’t satisfied.
§Name Resolution
As mentioned previously,Linker
is a form of name resolver. It will beusing the string-based names of imports on a module to attempt to select amatching item to hook up to it. This name resolution has two-levels ofnamespaces, a module level and a name level. Each item is defined within amodule and then has its own name. This basically follows the wasm standardfor modularization.
Names in aLinker
cannot be defined twice, but allowing duplicates byshadowing the previous definition can be controlled with theLinker::allow_shadowing
method.
§Commands and Reactors
TheLinker
type provides conveniences for working with WASI Commands andReactors through theLinker::module
method. This will automaticallyhandle instantiation and calling_start
and such as appropriatedepending on the inferred type of module.
§Type parameterT
It’s worth pointing out that the type parameterT
onLinker<T>
doesnot represent thatT
is stored within aLinker
. Rather theT
is usedto ensure that linker-defined functions and stores instantiated into all usethe same matchingT
as host state.
§MultipleStore
s
TheLinker
type is designed to be compatible, in some scenarios, withinstantiation in multipleStore
s. Specifically host-defined functionscreated inLinker
withLinker::func_new
,Linker::func_wrap
, andtheir async versions are compatible to instantiate into anyStore
. Thisenables programs which want to instantiate lots of modules to create oneLinker
value at program start up and use that continuously for eachStore
created over the lifetime of the program.
Note that onceStore
-owned items, such asGlobal
, are defined withinaLinker
then it is no longer compatible with anyStore
. At thatpoint only theStore
that owns theGlobal
can be used to instantiatemodules.
§MultipleEngine
s
TheLinker
type is not compatible with usage between multipleEngine
values. AnEngine
is provided when aLinker
is created and onlystores and items which originate from thatEngine
can be used with thisLinker
. If more than oneEngine
is used with aLinker
then thatmay cause a panic at runtime, similar to how if aFunc
is used with thewrongStore
that can also panic at runtime.
Implementations§
Source§impl<T>Linker<T>
impl<T>Linker<T>
Sourcepub fnallow_shadowing(&mut self, allow:bool) -> &mut Self
pub fnallow_shadowing(&mut self, allow:bool) -> &mut Self
Configures whether thisLinker
will shadow previous duplicatedefinitions of the same signature.
By default aLinker
will disallow duplicate definitions of the samesignature. This method, however, can be used to instead allow duplicatesand have the latest definition take precedence when linking modules.
§Examples
letmutlinker = Linker::<()>::new(&engine);linker.func_wrap("","", || {})?;// by default, duplicates are disallowedassert!(linker.func_wrap("","", || {}).is_err());// but shadowing can be configured to be allowed as welllinker.allow_shadowing(true);linker.func_wrap("","", || {})?;
Sourcepub fnallow_unknown_exports(&mut self, allow:bool) -> &mut Self
pub fnallow_unknown_exports(&mut self, allow:bool) -> &mut Self
Configures whether thisLinker
will allow unknown exports fromcommand modules.
By default aLinker
will error when unknown exports are encounteredin a command module while usingLinker::module
.
This method can be used to allow unknown exports from command modules.
§Examples
letmutlinker = Linker::new(&engine);linker.allow_unknown_exports(true);linker.module(&mutstore,"mod",&module)?;
Sourcepub fndefine_unknown_imports_as_traps(&mut self, module: &Module) ->Result<()>where T: 'static,
pub fndefine_unknown_imports_as_traps(&mut self, module: &Module) ->Result<()>where T: 'static,
Implement any imports of the givenModule
with a function which traps.
By default aLinker
will error when unknown imports are encounteredin a command module while usingLinker::module
.
This method can be used to allow unknown imports from command modules.
§Examples
letmutlinker = Linker::new(&engine);linker.define_unknown_imports_as_traps(&module)?;linker.instantiate(&mutstore,&module)?;
Sourcepub fndefine_unknown_imports_as_default_values( &mut self, store: &mut implAsContextMut<Data = T>, module: &Module,) ->Result<()>where T: 'static,
pub fndefine_unknown_imports_as_default_values( &mut self, store: &mut implAsContextMut<Data = T>, module: &Module,) ->Result<()>where T: 'static,
Implement any function imports of theModule
with a function thatignores 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
letmutlinker = Linker::new(&engine);linker.define_unknown_imports_as_default_values(&mutstore,&module)?;linker.instantiate(&mutstore,&module)?;
Sourcepub fndefine( &mut self, store: implAsContext<Data = T>, module: &str, name: &str, item: implInto<Extern>,) ->Result<&mut Self>where T: 'static,
pub fndefine( &mut self, store: implAsContext<Data = T>, module: &str, name: &str, item: implInto<Extern>,) ->Result<&mut Self>where T: 'static,
Defines a new item in thisLinker
.
This method will add a new definition, by name, to this instance ofLinker
. Themodule
andname
provided are what to name theitem
.
§Errors
Returns an error if themodule
andname
already identify an itemof the same type as theitem
provided and if shadowing is disallowed.For more information see the documentation onLinker
.
§Examples
letmutlinker = Linker::new(&engine);letty = GlobalType::new(ValType::I32, Mutability::Const);letglobal = Global::new(&mutstore, ty, Val::I32(0x1234))?;linker.define(&store,"host","offset", global)?;letwat =r#" (module (import "host" "offset" (global i32)) (memory 1) (data (global.get 0) "foo") )"#;letmodule = Module::new(&engine, wat)?;linker.instantiate(&mutstore,&module)?;
Sourcepub fndefine_name( &mut self, store: implAsContext<Data = T>, name: &str, item: implInto<Extern>,) ->Result<&mut Self>where T: 'static,
pub fndefine_name( &mut self, store: implAsContext<Data = T>, name: &str, item: implInto<Extern>,) ->Result<&mut Self>where T: 'static,
Same asLinker::define
, except only the name of the import isprovided, not a module name as well.
This is only relevant when working with the module linking proposalwhere one-level names are allowed (in addition to two-level names).Otherwise this method need not be used.
Sourcepub fnfunc_new( &mut self, module: &str, name: &str, ty:FuncType, func: implFn(Caller<'_, T>, &[Val], &mut [Val]) ->Result<()> +Send +Sync + 'static,) ->Result<&mut Self>where T: 'static,
pub fnfunc_new( &mut self, module: &str, name: &str, ty:FuncType, func: implFn(Caller<'_, T>, &[Val], &mut [Val]) ->Result<()> +Send +Sync + 'static,) ->Result<&mut Self>where T: 'static,
Creates aFunc::new
-style function named in this linker.
For more information seeLinker::func_wrap
.
§Panics
Panics if the given function type is not associated with the same engineas this linker.
Sourcepub unsafe fnfunc_new_unchecked( &mut self, module: &str, name: &str, ty:FuncType, func: implFn(Caller<'_, T>, &mut [ValRaw]) ->Result<()> +Send +Sync + 'static,) ->Result<&mut Self>where T: 'static,
pub unsafe fnfunc_new_unchecked( &mut self, module: &str, name: &str, ty:FuncType, func: implFn(Caller<'_, T>, &mut [ValRaw]) ->Result<()> +Send +Sync + 'static,) ->Result<&mut Self>where T: 'static,
Creates aFunc::new_unchecked
-style function named in this linker.
For more information seeLinker::func_wrap
.
§Panics
Panics if the given function type is not associated with the same engineas this linker.
Sourcepub fnfunc_new_async<F>( &mut self, module: &str, name: &str, ty:FuncType, func: F,) ->Result<&mut Self>
Available oncrate featuresasync
andcranelift
only.
pub fnfunc_new_async<F>( &mut self, module: &str, name: &str, ty:FuncType, func: F,) ->Result<&mut Self>
async
andcranelift
only.Creates aFunc::new_async
-style function named in this linker.
For more information seeLinker::func_wrap
.
§Panics
This method panics in the following situations:
This linker is not associated with anasyncconfig.
If the given function type is not associated with the same engine asthis linker.
Sourcepub fnfunc_wrap<Params, Args>( &mut self, module: &str, name: &str, func: implIntoFunc<T, Params, Args>,) ->Result<&mut Self>where T: 'static,
pub fnfunc_wrap<Params, Args>( &mut self, module: &str, name: &str, func: implIntoFunc<T, Params, Args>,) ->Result<&mut Self>where T: 'static,
Define a host function within this linker.
For information about how the host function operates, seeFunc::wrap
. That includes information about translating Rust typesto WebAssembly native types.
This method creates a host-provided function in this linker under theprovided name. This method is distinct in its capability to create aStore
-independent function. This means that thefunction defined here can be used to instantiate instances in multipledifferent stores, or in other words the function can be loaded intodifferent stores.
Note that the capability mentioned here applies to all otherhost-function-defining-methods onLinker
as well. All of them can beused to create instances ofFunc
within multiple stores. In amultithreaded program, for example, this means that the host functionscould be called concurrently if different stores are executing ondifferent threads.
§Errors
Returns an error if themodule
andname
already identify an itemof the same type as theitem
provided and if shadowing is disallowed.For more information see the documentation onLinker
.
§Examples
letmutlinker = 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| {// ...})?;letwat =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))) )"#;letmodule = Module::new(&engine, wat)?;// instantiate in multiple different storesfor _ in0..10{letmutstore = Store::new(&engine, ()); linker.instantiate(&mutstore,&module)?;}
Sourcepub fnfunc_wrap_async<F, Params:WasmTyList, Args:WasmRet>( &mut self, module: &str, name: &str, func: F,) ->Result<&mut Self>
Available oncrate featureasync
only.
pub fnfunc_wrap_async<F, Params:WasmTyList, Args:WasmRet>( &mut self, module: &str, name: &str, func: F,) ->Result<&mut Self>
async
only.Asynchronous analog ofLinker::func_wrap
.
Sourcepub fninstance( &mut self, store: implAsContextMut<Data = T>, module_name: &str, instance:Instance,) ->Result<&mut Self>where T: 'static,
pub fninstance( &mut self, store: implAsContextMut<Data = T>, module_name: &str, instance:Instance,) ->Result<&mut Self>where T: 'static,
Convenience wrapper to define an entireInstance
in this linker.
This function is a convenience wrapper aroundLinker::define
whichwill define all exports oninstance
into this linker. The module namefor each export ismodule_name
, and the name for each export is thename in the instance itself.
Note that when this API is used theLinker
is no longer compatiblewith multi-Store
instantiation because the itemsdefined within this store will belong to thestore
provided, and onlythestore
provided.
§Errors
Returns an error if the any item is redefined twice in this linker (forexample the samemodule_name
was already defined) and shadowing isdisallowed, or ifinstance
comes from a differentStore
than thisLinker
originally was createdwith.
§Panics
Panics ifinstance
does not belong tostore
.
§Examples
letmutlinker = Linker::new(&engine);// Instantiate a small instance...letwat =r#"(module (func (export "run") ))"#;letmodule = Module::new(&engine, wat)?;letinstance = linker.instantiate(&mutstore,&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(&mutstore,"instance1", instance)?;letwat =r#" (module (import "instance1" "run" (func $instance1_run)) (func (export "run") call $instance1_run ) )"#;letmodule = Module::new(&engine, wat)?;letinstance = linker.instantiate(&mutstore,&module)?;
Sourcepub fnmodule( &mut self, store: implAsContextMut<Data = T>, module_name: &str, module: &Module,) ->Result<&mut Self>where T: 'static,
pub fnmodule( &mut self, store: implAsContextMut<Data = T>, module_name: &str, module: &Module,) ->Result<&mut Self>where T: 'static,
Define automatic instantiations of aModule
in this linker.
This automatically handlesCommands and Reactors instantiation andinitialization.
Exported functions of a Command module may be called directly, howeverinstead of having a single instance which is reused for each call,each call creates a new instance, which lives for the duration of thecall. The imports of the Command are resolved once, and reused foreach instantiation, so all dependencies need to be present at the timewhenLinker::module
is called.
For Reactors, a single instance is created, and an initializationfunction is called, and then its exports may be called.
Ordinary modules which don’t declare themselves to be either Commandsor Reactors are treated as Reactors without any initialization calls.
§Errors
Returns an error if the any item is redefined twice in this linker (forexample the samemodule_name
was already defined) and shadowing isdisallowed, ifinstance
comes from a differentStore
than thisLinker
originally was createdwith, or if a Reactor initialization function traps.
§Panics
Panics if any item used to instantiate the providedModule
is notowned bystore
, or if thestore
provided comes from a differentEngine
than thisLinker
.
§Examples
letmutlinker = 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.letwat =r#"(module (func (export "run") ))"#;letmodule = Module::new(&engine, wat)?;linker.module(&mutstore,"instance1",&module)?;letwat =r#" (module (import "instance1" "run" (func $instance1_run)) (func (export "run") call $instance1_run ) )"#;letmodule = Module::new(&engine, wat)?;letinstance = linker.instantiate(&mutstore,&module)?;
For a Command, a new instance is created for each call.
letmutlinker = 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.letwat =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) ) )"#;letmodule = Module::new(&engine, wat)?;linker.module(&mutstore,"commander",&module)?;letrun = linker.get_default(&mutstore,"")?.typed::<(), ()>(&store)?.clone();run.call(&mutstore, ())?;run.call(&mutstore, ())?;run.call(&mutstore, ())?;letwat =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 ) )"#;letmodule = Module::new(&engine, wat)?;linker.module(&mutstore,"",&module)?;letrun = linker.get(&mutstore,"","run").unwrap().into_func().unwrap();letcount = run.typed::<(), i32>(&store)?.call(&mutstore, ())?;assert_eq!(count,0,"a Command should get a fresh instance on each invocation");
Sourcepub async fnmodule_async( &mut self, store: implAsContextMut<Data = T>, module_name: &str, module: &Module,) ->Result<&mut Self>where T:Send + 'static,
Available oncrate featuresasync
andcranelift
only.
pub async fnmodule_async( &mut self, store: implAsContextMut<Data = T>, module_name: &str, module: &Module,) ->Result<&mut Self>where T:Send + 'static,
async
andcranelift
only.Define automatic instantiations of aModule
in this linker.
This is the same asLinker::module
, except for asyncStore
s.
Sourcepub fnalias( &mut self, module: &str, name: &str, as_module: &str, as_name: &str,) ->Result<&mut Self>
pub fnalias( &mut self, module: &str, name: &str, as_module: &str, as_name: &str,) ->Result<&mut Self>
Aliases one item’s name as another.
This method will alias an item with the specifiedmodule
andname
under a new name ofas_module
andas_name
.
§Errors
Returns an error if any shadowing violations happen while defining newitems, or if the original item wasn’t defined.
Sourcepub fnalias_module(&mut self, module: &str, as_module: &str) ->Result<()>
pub fnalias_module(&mut self, module: &str, as_module: &str) ->Result<()>
Aliases one module’s name as another.
This method will alias all currently defined undermodule
to also bedefined under the nameas_module
too.
§Errors
Returns an error if any shadowing violations happen while defining newitems.
Sourcepub fninstantiate( &self, store: implAsContextMut<Data = T>, module: &Module,) ->Result<Instance>where T: 'static,
pub fninstantiate( &self, store: implAsContextMut<Data = T>, module: &Module,) ->Result<Instance>where T: 'static,
Attempts to instantiate themodule
provided.
This method will attempt to assemble a list of imports that correspondto the imports required by theModule
provided. This listof imports is then passed toInstance::new
to continue theinstantiation process.
Each import ofmodule
will be looked up in thisLinker
and musthave previously been defined. If it was previously defined with anincorrect signature or if it was not previously defined then an errorwill be returned because the import can not be satisfied.
Per the WebAssembly spec, instantiation includes running the module’sstart 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 becauseinstantiation itself may fail. For information on instantiationfailures seeInstance::new
. If an import is not found, the errormay be downcast to anUnknownImportError
.
§Panics
Panics if any item used to instantiatemodule
is not owned bystore
. Additionally this will panic if theEngine
that thestore
belongs to is different than thisLinker
.
§Examples
letmutlinker = Linker::new(&engine);linker.func_wrap("host","double", |x: i32| x *2)?;letwat =r#" (module (import "host" "double" (func (param i32) (result i32))) )"#;letmodule = Module::new(&engine, wat)?;linker.instantiate(&mutstore,&module)?;
Sourcepub async fninstantiate_async( &self, store: implAsContextMut<Data = T>, module: &Module,) ->Result<Instance>where T:Send + 'static,
Available oncrate featureasync
only.
pub async fninstantiate_async( &self, store: implAsContextMut<Data = T>, module: &Module,) ->Result<Instance>where T:Send + 'static,
async
only.Attempts to instantiate themodule
provided. This is the same asLinker::instantiate
, except for asyncStore
s.
Sourcepub fninstantiate_pre(&self, module: &Module) ->Result<InstancePre<T>>where T: 'static,
pub fninstantiate_pre(&self, module: &Module) ->Result<InstancePre<T>>where T: 'static,
Performs all checks necessary for instantiatingmodule
with thislinker, except that instantiation doesn’t actually finish.
This method is used for front-loading type-checking information as wellas collecting the imports to use to instantiate a module with. ThereturnedInstancePre
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 anUnknownImportError
ifthe module has any unresolvable imports.
§Examples
letmutlinker = Linker::new(&engine);linker.func_wrap("host","double", |x: i32| x *2)?;letwat =r#" (module (import "host" "double" (func (param i32) (result i32))) )"#;letmodule = Module::new(&engine, wat)?;letinstance_pre = linker.instantiate_pre(&module)?;// Finish instantiation after the type-checking has all completed...letinstance = instance_pre.instantiate(&mutstore)?;// ... and we can even continue to keep instantiating if desired!instance_pre.instantiate(&mutstore)?;instance_pre.instantiate(&mutstore)?;// 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.letmutnew_store = Store::new(&engine, ());instance_pre.instantiate(&mutnew_store)?;
Sourcepub fniter<'a: 'p, 'p>( &'a self, store: implAsContextMut<Data = T> + 'p,) -> implIterator<Item = (&'astr, &'astr,Extern)> + 'pwhere T: 'static,
pub fniter<'a: 'p, 'p>( &'a self, store: implAsContextMut<Data = T> + 'p,) -> implIterator<Item = (&'astr, &'astr,Extern)> + 'pwhere T: 'static,
Returns an iterator over all items defined in thisLinker
, inarbitrary order.
The iterator returned will yield 3-tuples where the first two elementsare the module name and item name for the external item, and the thirditem is the item itself that is defined.
Note that multipleExtern
items may be defined for the samemodule/name pair.
§Panics
This function will panic if thestore
provided does not come from thesameEngine
that this linker was created with.
Sourcepub fnget( &self, store: implAsContextMut<Data = T>, module: &str, name: &str,) ->Option<Extern>where T: 'static,
pub fnget( &self, store: implAsContextMut<Data = T>, module: &str, name: &str,) ->Option<Extern>where T: 'static,
Sourcepub fnget_by_import( &self, store: implAsContextMut<Data = T>, import: &ImportType<'_>,) ->Option<Extern>where T: 'static,
pub fnget_by_import( &self, store: implAsContextMut<Data = T>, import: &ImportType<'_>,) ->Option<Extern>where T: 'static,
Sourcepub fnget_default( &self, store: implAsContextMut<Data = T>, module: &str,) ->Result<Func>where T: 'static,
pub fnget_default( &self, store: implAsContextMut<Data = T>, module: &str,) ->Result<Func>where T: 'static,
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 bystore
. Thisfunction will also panic if thestore
provided does not come from thesameEngine
that this linker was created with.
Trait Implementations§
Auto Trait Implementations§
impl<T>Freeze forLinker<T>
impl<T> !RefUnwindSafe forLinker<T>
impl<T>Send forLinker<T>
impl<T>Sync forLinker<T>
impl<T>Unpin forLinker<T>
impl<T> !UnwindSafe forLinker<T>
Blanket Implementations§
Source§impl<T>BorrowMut<T> for Twhere T: ?Sized,
impl<T>BorrowMut<T> for Twhere T: ?Sized,
Source§fnborrow_mut(&mut self) ->&mut T
fnborrow_mut(&mut self) ->&mut T
Source§impl<T>CloneToUninit for Twhere T:Clone,
impl<T>CloneToUninit for Twhere T:Clone,
Source§impl<T>IntoEither for T
impl<T>IntoEither for T
Source§fninto_either(self, into_left:bool) ->Either<Self, Self>ⓘ
fninto_either(self, into_left:bool) ->Either<Self, Self>ⓘ
self
into aLeft
variant ofEither<Self, Self>
ifinto_left
istrue
.Convertsself
into aRight
variant ofEither<Self, Self>
otherwise.Read moreSource§fninto_either_with<F>(self, into_left: F) ->Either<Self, Self>ⓘ
fninto_either_with<F>(self, into_left: F) ->Either<Self, Self>ⓘ
self
into aLeft
variant ofEither<Self, Self>
ifinto_left(&self)
returnstrue
.Convertsself
into aRight
variant ofEither<Self, Self>
otherwise.Read more