I'm developing a proof-of-concept to understand how to implement a resource (specified in a .wit file for a WASM module) in a Wasmtime host.
My setup:
wit-bindgen
My ultimate goal is to enable nested JSON (objects and arrays) in the interface between the host and WASM module, as suggested in this Component Model discussion.
I've created a JSON structure in the host:
// Define the json variant
enum Json {
Null, Boolean(bool),
Number(f64),
String(String),
Array(Vec<Resource<LazyJson>>),
Object(Vec<(String, Resource<LazyJson>)>),
}
// Implement the LazyJson resource
struct LazyJson;
impl LazyJson {
fn get(&self) -> Json {
println!("LazyJson::get called!");
Json::String("dummy value".to_string())
}
}
I've set up the linker and store:
let mut linker = Linker::new(&engine); // Using wasmtime::runtime::component::linker
wasmtime_wasi::add_to_linker_sync(&mut linker)?;
let mut store = Store::new(
&engine,
MyState {
ctx: WasiCtxBuilder::new().build(),
table: ResourceTable::new(),
lazy_json: LazyJson,
},
);
I'm struggling with how to add the resource to the linker. I believe I need to do something like:
linker.root().resource("lazy-json", ResourceType, dtor);
But I'm uncertain how to specify the ResourceType
and dtor
(destructor).
After adding the resource to the linker, I need to wrap the function, perhaps something like:
linker.root().func_wrap("lazy-json", "get", ???)
Here I'm unsure what the arguments should be.
Are there any examples demonstrating how to in a host implement and register a resource defined in .wit
for a WASM module using Wasmtime and the Component Model? I'm looking for guidance on:
Even a simple "hello world" example would be helpful. Thanks!
Hello!
Currently there's not great documentation for this, and the "best" location is to look around at the test in the tests/all/component_model/*.rs
. The reason for this is that it's expected that hosts primarily use WIT and generated bindings (which looks like this). Given though that the guest is using wit-bindgen
is there a reason to not use the same WIT to generate bindings on the host? The end-result of bindgen is an add_to_linker
function and you can still add, for example, WASI to the linker so the WIT files doesn't have to be an exhaustive definition of the world you're using, just a partial enough piece for the JSON wrapper.
In addition to some answers below you can also explore the generated code of wasmtime::component::bindgen!
by using cargo expand
too (a few more words on debugging here too)
How to properly define the resource type
You're right that [Linker::resource
]https://docs.rs/wasmtime/latest/wasmtime/component/struct.LinkerInstance.html#method.resource) is what you want. You'll use ResourceType::host::<LazyJson>()
here.
How to create a destructor for the resource
This is up to you. A resource is a u32
on the host and you get to decide what to do with that u32
. Most of the time though it's a ResourceTable
where the destructor is removing the index from the table.
How to correctly wrap and expose the resource functions to the WASM module
The function you'll define has type fn(StoreContextMut<'_, T>, Resource<LazyJson>) -> wasmtime::Result<Json>
. Defining the Json
type is possible with #[derive(ComponentType)]
but I'd recommend using bindgen!
instead as it'll be far less error-prone.
Last updated: Feb 27 2025 at 23:03 UTC