Component in wasmtime::component - Rust (original) (raw)
pub struct Component { /* private fields */ }
Available on crate features runtime
and component-model
only.
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 ofModule in the component embedding API.
A Component can be turned into anInstance through aLinker. Components are safe to share across threads. The compilation model of a component is the same as that ofa module which is to say:
- Compilation happens synchronously during Component::new.
- The result of compilation can be saved into storage withComponent::serialize.
- A previously compiled artifact can be parsed withComponent::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 asComponent has the same high-level API.
Available on crate features cranelift
or winch
only.
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 aWebAssembly 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))")?;
Available on crate feature std
and (crate features cranelift
or winch
) only.
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.
Available on crate features cranelift
or winch
only.
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.
Same as Module::deserialize_raw, but for components.
See Component::deserialize for additional information; this method works identically except that it will not create a copy of the provided memory but will use it directly.
§Unsafety
All of the safety notes from Component::deserialize apply here as well with the additional constraint that the code memory provide by memory
lives for as long as the module and is nevery externally modified for the lifetime of the deserialized module.
Available on crate feature std
only.
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);
Returns a summary of the resources required to instantiate thisComponent.
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 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mn>1</mn><mo stretchy="false">(</mo><mi>i</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>a</mi><mi>n</mi><mi>t</mi><mi>i</mi><mi>a</mi><mi>t</mi><mi>e</mi><mo stretchy="false">(</mo><mi>m</mi><mi>o</mi><mi>d</mi><mi>u</mi><mi>l</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">i1 (instantiate (module </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">i</span><span class="mord">1</span><span class="mopen">(</span><span class="mord mathnormal">in</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">an</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ia</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal">m</span><span class="mord mathnormal">o</span><span class="mord mathnormal">d</span><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">e</span></span></span></span>m)))
(core instance <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mn>2</mn><mo stretchy="false">(</mo><mi>i</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>a</mi><mi>n</mi><mi>t</mi><mi>i</mi><mi>a</mi><mi>t</mi><mi>e</mi><mo stretchy="false">(</mo><mi>m</mi><mi>o</mi><mi>d</mi><mi>u</mi><mi>l</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">i2 (instantiate (module </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">i</span><span class="mord">2</span><span class="mopen">(</span><span class="mord mathnormal">in</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">an</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ia</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal">m</span><span class="mord mathnormal">o</span><span class="mord mathnormal">d</span><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">e</span></span></span></span>m)))
(core instance <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mn>3</mn><mo stretchy="false">(</mo><mi>i</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>a</mi><mi>n</mi><mi>t</mi><mi>i</mi><mi>a</mi><mi>t</mi><mi>e</mi><mo stretchy="false">(</mo><mi>m</mi><mi>o</mi><mi>d</mi><mi>u</mi><mi>l</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">i3 (instantiate (module </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">i</span><span class="mord">3</span><span class="mopen">(</span><span class="mord mathnormal">in</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">an</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ia</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal">m</span><span class="mord mathnormal">o</span><span class="mord mathnormal">d</span><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">e</span></span></span></span>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);
Returns the range, in the host’s address space, that this module’s compiled code resides at.
For more information seeModule::image_range.
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.
Looks up a specific export of this component by name
optionally nested within the instance
provided.
This method is primarily used to acquire a ComponentExportIndexwhich 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: atypes::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.
The returned types::ComponentItem is more expensive to calculate than the ComponentExportIndex. If you only consume theComponentExportIndex, use the related methodSelf::get_export_index instead.
Instance has a corresponding methodInstance::get_export.
§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 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo stretchy="false">(</mo><mi>i</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>a</mi><mi>n</mi><mi>t</mi><mi>i</mi><mi>a</mi><mi>t</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">i (instantiate </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">i</span><span class="mopen">(</span><span class="mord mathnormal">in</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">an</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ia</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span></span></span></span>m))
(func (export "f")
(canon lift (core func $i "f")))
)
"#,
)?;
// Perform a lookup of the function "f" before instantiaton.
let (ty, export) = component.get_export(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)?;
// ...