Stream: wasmtime

Topic: Auto-Generating more Traits for Components


view this post on Zulip Antoine Lavandier (Nov 04 2025 at 10:22):

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:

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 ?

view this post on Zulip Pat Hickey (Nov 04 2025 at 18:19):

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

view this post on Zulip Antoine Lavandier (Nov 06 2025 at 11:16):

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

view this post on Zulip Antoine Lavandier (Nov 06 2025 at 11:35):

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() {}

view this post on Zulip Antoine Lavandier (Nov 06 2025 at 11:36):

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<()>;
}

view this post on Zulip Alex Crichton (Nov 06 2025 at 15:42):

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.

view this post on Zulip Antoine Lavandier (Nov 06 2025 at 16:10):

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

view this post on Zulip Alex Crichton (Nov 06 2025 at 16:33):

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