Hi,
While working with components, I found myself wanting to be generics on Components in the same way that Components are generic on the Host.
So If you're amenable to such a change, I would like to work on modifying component::bindgen! to add the following things:
IsComponent<T:Host> trait that contains add_to_linker and instantiate/instantiate_aysnc. This would require a IsComponent<T>present in wasmtime::component Together these would make code like this possible:
// A world exporting a foo interface and importing a bar interface.
A FooGuest trait is generated and implement by the generated type Baz;
bindgen!({world: "baz"});
struct MyHost;
impl bar::Host for MyHost {};
fn start_foo_component<H: Host, C:IsAComponent<H> + FooGuest>(store: &mut Store<T>, linker:&mut Linker<T>, component: &Component) -> C {
C::add_to_linker::<_, HasSelf<_>>(linker, |state| state});
C::instantiate(store, component, linker).unwrap()
}
fn run_foo_component<H: Host, C: FooGuest>(store: &mut Store<H>, instance: C) {
instance.call_foo(store).unwrap();
}
What do you think ?
I don't think I understand your proposal enough from the above. How complex is it to make these changes? It would be useful for me to see the code output by bindgen for an example before and after side-by-side
So I've trying working on the first point, turns out that it's more complicated than I thought because of the existence of auto-generated LinkOptions. I wanted to show a before/after generated code through the bindgen_examples modules but running cargo doc -p wasmtime --features "component-model, runtime, async" breaks the bindgen_examples
In any case here's a before after of what I've currently got :
Not expanded:
use wasmtime::component::bindgen;
bindgen!({
inline: r#"
package my:project;
world hello-world {
import name: func() -> string;
export greet: func();
}
"#,
});
fn main () {
}
before after diff:
diffoscope before.rs after.rs
--- before.rs
+++ after.rs
@@ -266,9 +266,29 @@
wasmtime::component::TypedFunc::<(), ()>::new_unchecked(self.greet)
};
let () = callee.call(store.as_context_mut(), ())?;
callee.post_return(store.as_context_mut())?;
Ok(())
}
}
+ impl<T, D> wasmtime::component::ComponentInstance<T, D> for HelloWorld
+ where
+ T: 'static,
+ D: HelloWorldImportsWithStore,
+ for<'a> D::Data<'a>: HelloWorldImports,
+ {
+ fn instantiate(
+ store: impl wasmtime::AsContextMut<Data = T>,
+ component: &wasmtime::component::Component,
+ linker: &wasmtime::component::Linker<T>,
+ ) -> wasmtime::Result<Self> {
+ Self::instantiate(store, component, linker)
+ }
+ fn add_to_linker(
+ linker: &mut wasmtime::component::Linker<T>,
+ host_getter: fn(&mut T) -> D::Data<'_>,
+ ) -> wasmtime::Result<()> {
+ Self::add_to_linker::<T, D>(linker, host_getter)
+ }
+ }
};
fn main() {}
Currently this only adds code that implements the (new) wasmtime::component::ComponentInstance trait.
Here's its definition:
/// Trait that allows to start any auto-generated component. See [``]
///
/// [`bindgen!`](crate::component::bindgen) will implement this for T, D that have the
/// proper bounds
pub trait ComponentInstance<T, D: crate::component::HasData>: Sized {
/// Wrapper on the autogenerated Self::instantiate
fn instantiate(
store: impl AsContextMut<Data = T>,
component: &Component,
linker: &Linker<T>
) -> crate::Result<Self>;
/// Wrapper on the autogenerated Self::add_to_linker
fn add_to_linker(
linker: &mut Linker<T>,
host_getter: fn(&mut T) -> D::Data<'_>,
) -> crate::Result<()>;
}
That seems reasonable to me yeah. I migth bindgen ComponentInstance to something like BindgenWorld to make it clear that it's from bindgen!, or maybe even World or WitWorld, but that's just a minor detail.
Any idea on how to deal with worlds that have a options: &LinkOptions argument in their add_to_linker ? This is a generated type so I don't see how to deal with that. Adding another generic is always an option I guess...
I think it'd be reasonable to avoid exposing that in the trait and use LinkOptions::default(), and if customization is needed the raw functions can be used
Last updated: Dec 06 2025 at 06:05 UTC