Struct Component
pub struct Component { /* private fields */ }
Expand description
A compiled WebAssembly Component.
This structure represents a compiled component that is ready to be
instantiated. This owns a region of virtual memory which contains executable
code compiled from a WebAssembly binary originally. This is the analog of
Module
in the component embedding API.
A Component
can be turned into an
Instance
through a
Linker
. Component
s are safe to share
across threads. The compilation model of a component is the same as that of
a module which is to say:
- Compilation happens synchronously during
Component::new
. - The result of compilation can be saved into storage with
Component::serialize
. - A previously compiled artifact can be parsed with
Component::deserialize
. - No compilation happens at runtime for a component — everything is done
by the time
Component::new
returns.
§Components and Clone
Using clone
on a Component
is a cheap operation. It will not create an
entirely new component, but rather just a new reference to the existing
component. In other words it’s a shallow copy, not a deep copy.
§Examples
For example usage see the documentation of Module
as
Component
has the same high-level API.
Implementations§
§impl Component
impl Component
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component, Error>
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component, Error>
Compiles a new WebAssembly component from the in-memory list of bytes provided.
The bytes
provided can either be the binary or text format of a
WebAssembly component. Note that the text format requires the wat
feature of this crate to be enabled. This API does not support
streaming compilation.
This function will synchronously validate the entire component, including all core modules, and then compile all components, modules, etc., found within the provided bytes.
§Errors
This function may fail and return an error. Errors may include situations such as:
- The binary provided could not be decoded because it’s not a valid WebAssembly binary
- The WebAssembly binary may not validate (e.g. contains type errors)
- Implementation-specific limits were exceeded with a valid binary (for example too many locals)
- The wasm binary may use features that are not enabled in the
configuration of
engine
- If the
wat
feature is enabled and the input is text, then it may be rejected if it fails to parse.
The error returned should contain full information about why compilation failed.
§Examples
The new
function can be invoked with a in-memory array of bytes:
let component = Component::new(&engine, &wasm_bytes)?;
Or you can also pass in a string to be parsed as the wasm text format:
let component = Component::new(&engine, "(component (core module))")?;
pub fn from_file(
engine: &Engine,
file: impl AsRef<Path>,
) -> Result<Component, Error>
pub fn from_file( engine: &Engine, file: impl AsRef<Path>, ) -> Result<Component, Error>
Compiles a new WebAssembly component from a wasm file on disk pointed
to by file
.
This is a convenience function for reading the contents of file
on
disk and then calling Component::new
.
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Component, Error>
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Component, Error>
Compiles a new WebAssembly component from the in-memory wasm image provided.
This function is the same as Component::new
except that it does not
accept the text format of WebAssembly. Even if the wat
feature
is enabled an error will be returned here if binary
is the text
format.
For more information on semantics and errors see Component::new
.
pub unsafe fn deserialize(
engine: &Engine,
bytes: impl AsRef<[u8]>,
) -> Result<Component, Error>
pub unsafe fn deserialize( engine: &Engine, bytes: impl AsRef<[u8]>, ) -> Result<Component, Error>
Same as Module::deserialize
, but for components.
Note that the bytes referenced here must contain contents previously
produced by Engine::precompile_component
or
Component::serialize
.
For more information see the Module::deserialize
method.
§Unsafety
The unsafety of this method is the same as that of the
Module::deserialize
method.
pub unsafe fn deserialize_file(
engine: &Engine,
path: impl AsRef<Path>,
) -> Result<Component, Error>
pub unsafe fn deserialize_file( engine: &Engine, path: impl AsRef<Path>, ) -> Result<Component, Error>
Same as Module::deserialize_file
, but for components.
Note that the file referenced here must contain contents previously
produced by Engine::precompile_component
or
Component::serialize
.
For more information see the Module::deserialize_file
method.
§Unsafety
The unsafety of this method is the same as that of the
Module::deserialize_file
method.
pub fn component_type(&self) -> Component
pub fn component_type(&self) -> Component
Returns the type of this component as a types::Component
.
This method enables runtime introspection of the type of a component before instantiation, if necessary.
§Component types and Resources
An important point to note here is that the precise type of imports and
exports of a component change when it is instantiated with respect to
resources. For example a Component
represents an un-instantiated
component meaning that its imported resources are represented as abstract
resource types. These abstract types are not equal to any other
component’s types.
For example:
let a = Component::new(&engine, r#"
(component (import "x" (type (sub resource))))
"#)?;
let b = Component::new(&engine, r#"
(component (import "x" (type (sub resource))))
"#)?;
let (_, a_ty) = a.component_type().imports(&engine).next().unwrap();
let (_, b_ty) = b.component_type().imports(&engine).next().unwrap();
let a_ty = match a_ty {
ComponentItem::Resource(ty) => ty,
_ => unreachable!(),
};
let b_ty = match b_ty {
ComponentItem::Resource(ty) => ty,
_ => unreachable!(),
};
assert!(a_ty != b_ty);
Additionally, however, these abstract types are “substituted” during instantiation meaning that a component type will appear to have changed once it is instantiated.
// Here this component imports a resource and then exports it as-is
// which means that the export is equal to the import.
let a = Component::new(&engine, r#"
(component
(import "x" (type $x (sub resource)))
(export "x" (type $x))
)
"#)?;
let (_, import) = a.component_type().imports(&engine).next().unwrap();
let (_, export) = a.component_type().exports(&engine).next().unwrap();
let import = match import {
ComponentItem::Resource(ty) => ty,
_ => unreachable!(),
};
let export = match export {
ComponentItem::Resource(ty) => ty,
_ => unreachable!(),
};
assert_eq!(import, export);
// However after instantiation the resource type "changes"
let mut store = Store::new(&engine, ());
let mut linker = Linker::new(&engine);
linker.root().resource("x", ResourceType::host::<()>(), |_, _| Ok(()))?;
let instance = linker.instantiate(&mut store, &a)?;
let instance_ty = instance.get_resource(&mut store, "x").unwrap();
// Here `instance_ty` is not the same as either `import` or `export`,
// but it is equal to what we provided as an import.
assert!(instance_ty != import);
assert!(instance_ty != export);
assert!(instance_ty == ResourceType::host::<()>());
Finally, each instantiation of an exported resource from a component is considered “fresh” for all instantiations meaning that different instantiations will have different exported resource types:
let a = Component::new(&engine, r#"
(component
(type $x (resource (rep i32)))
(export "x" (type $x))
)
"#)?;
let mut store = Store::new(&engine, ());
let linker = Linker::new(&engine);
let instance1 = linker.instantiate(&mut store, &a)?;
let instance2 = linker.instantiate(&mut store, &a)?;
let x1 = instance1.get_resource(&mut store, "x").unwrap();
let x2 = instance2.get_resource(&mut store, "x").unwrap();
// Despite these two resources being the same export of the same
// component they come from two different instances meaning that their
// types will be unique.
assert!(x1 != x2);
pub fn serialize(&self) -> Result<Vec<u8>, Error>
pub fn serialize(&self) -> Result<Vec<u8>, Error>
Same as Module::serialize
, except for a component.
Note that the artifact produced here must be passed to
Component::deserialize
and is not compatible for use with
Module
.
pub fn resources_required(&self) -> Option<ResourcesRequired>
pub fn resources_required(&self) -> Option<ResourcesRequired>
Returns a summary of the resources required to instantiate this
Component
.
Note that when a component imports and instantiates another component or
core module, we cannot determine ahead of time how many resources
instantiating this component will require, and therefore this method
will return None
in these scenarios.
Potential uses of the returned information:
-
Determining whether your pooling allocator configuration supports instantiating this component.
-
Deciding how many of which
Component
you want to instantiate within a fixed amount of resources, e.g. determining whether to create 5 instances of component X or 10 instances of component Y.
§Example
use wasmtime::{Config, Engine, component::Component};
let mut config = Config::new();
config.wasm_multi_memory(true);
config.wasm_component_model(true);
let engine = Engine::new(&config)?;
let component = Component::new(&engine, &r#"
(component
;; Define a core module that uses two memories.
(core module $m
(memory 1)
(memory 6)
)
;; Instantiate that core module three times.
(core instance $i1 (instantiate (module $m)))
(core instance $i2 (instantiate (module $m)))
(core instance $i3 (instantiate (module $m)))
)
"#)?;
let resources = component.resources_required()
.expect("this component does not import any core modules or instances");
// Instantiating the component will require allocating two memories per
// core instance, and there are three instances, so six total memories.
assert_eq!(resources.num_memories, 6);
assert_eq!(resources.max_initial_memory_size, Some(6));
// The component doesn't need any tables.
assert_eq!(resources.num_tables, 0);
assert_eq!(resources.max_initial_table_size, None);
pub fn image_range(&self) -> Range<*const u8> ⓘ
pub fn image_range(&self) -> Range<*const u8> ⓘ
Returns the range, in the host’s address space, that this module’s compiled code resides at.
For more information see
Module::image_range
.
pub fn initialize_copy_on_write_image(&self) -> Result<(), Error>
pub fn initialize_copy_on_write_image(&self) -> Result<(), Error>
Force initialization of copy-on-write images to happen here-and-now instead of when they’re requested during first instantiation.
When copy-on-write memory initialization is enabled then Wasmtime will lazily create the initialization image for a component. This method can be used to explicitly dictate when this initialization happens.
Note that this largely only matters on Linux when memfd is used. Otherwise the copy-on-write image typically comes from disk and in that situation the creation of the image is trivial as the image is always sourced from disk. On Linux, though, when memfd is used a memfd is created and the initialization image is written to it.
Also note that this method is not required to be called, it’s available as a performance optimization if required but is otherwise handled automatically.
pub fn export_index(
&self,
instance: Option<&ComponentExportIndex>,
name: &str,
) -> Option<(ComponentItem, ComponentExportIndex)>
pub fn export_index( &self, instance: Option<&ComponentExportIndex>, name: &str, ) -> Option<(ComponentItem, ComponentExportIndex)>
Looks up a specific export of this component by name
optionally nested
within the instance
provided.
This method is primarily used to acquire a ComponentExportIndex
which can be used with Instance
when
looking up exports. Export lookup with ComponentExportIndex
can
skip string lookups at runtime and instead use a more efficient
index-based lookup.
This method takes a few arguments:
engine
- the engine that was used to compile this component.instance
- an optional “parent instance” for the export being looked up. If this isNone
then the export is looked up on the root of the component itself, and otherwise the export is looked up on theinstance
specified. Note thatinstance
must have come from a previous invocation of this method.name
- the name of the export that’s being looked up.
If the export is located then two values are returned: a
types::ComponentItem
which enables introspection about the type of
the export and a ComponentExportIndex
. The index returned notably
implements the InstanceExportLookup
trait which enables using it
with Instance::get_func
for
example.
§Examples
use wasmtime::{Engine, Store};
use wasmtime::component::{Component, Linker};
use wasmtime::component::types::ComponentItem;
let engine = Engine::default();
let component = Component::new(
&engine,
r#"
(component
(core module $m
(func (export "f"))
)
(core instance $i (instantiate $m))
(func (export "f")
(canon lift (core func $i "f")))
)
"#,
)?;
// Perform a lookup of the function "f" before instantiaton.
let (ty, export) = component.export_index(None, "f").unwrap();
assert!(matches!(ty, ComponentItem::ComponentFunc(_)));
// After instantiation use `export` to lookup the function in question
// which notably does not do a string lookup at runtime.
let mut store = Store::new(&engine, ());
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
let func = instance.get_typed_func::<(), ()>(&mut store, &export)?;
// ...
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Component
impl !RefUnwindSafe for Component
impl Send for Component
impl Sync for Component
impl Unpin for Component
impl !UnwindSafe for Component
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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