wiggle::wasmtime_crate::component

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. Components are safe to share across threads. The compilation model of a component is the same as that of a module which is to say:

§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

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>

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>

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>

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>

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

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>

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>

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>

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>

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)>

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 is None then the export is looked up on the root of the component itself, and otherwise the export is looked up on the instance specified. Note that instance 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)?;
// ...

pub fn engine(&self) -> &Engine

Returns the Engine that this Component was compiled by.

Trait Implementations§

§

impl Clone for Component

§

fn clone(&self) -> Component

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

Auto Trait Implementations§

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