Stream: wasmtime

Topic: bindgen! generated types and structs in Rust


view this post on Zulip Bozhidar Manev (May 05 2025 at 15:21):

Hi, I want to introduce host bindings to my project instead of manually setting and calling functions from components. making this change introduced some obstacles. Before I was able to use the Rust types by having them implement Component Model and either/both Lift or/and Lower:

#[derive(Debug, ComponentType, Lift, Serialize)]
#[component(record)]
pub(crate) struct Event {
    id: String,
    content: Vec<u8>,
}

world.wit

    record event {
        id: string,
        content: byte-array,
    }

Now using the host bindings from bindgen!, there is this type that implements Lower, Lift, ComponentType, etc.:

#[component(record)]
    pub struct Event {
        #[component(name = "id")]
        pub id: wasmtime::component::__internal::String,
        #[component(name = "content")]
        pub content: ByteArray,
    }

I thought that in my code (a simplified version) the following would work:
export execute: func()-> result<event>

fn exexute_in_component()-> wasmtime::Result<Result<Event, ()>>{
        // --- some code ---
        let instance = Guest::instanciate(...);
        let result: Result<Result<bindings::host::Event, ()>, anyhow::Error> = instance::call_execute();
        result
        // prompts the error from the next example
}

but direct conversion is not allowed by the compiler:

let a: Event = bindings::host::Event{id: "qwerty".to_string(), content: Vec::new()};
// expected `persistence::Event`, found `bindings::host::Event`
// = note: `bindings::host::Event` and `persistence::Event` have similar names, but are actually distinct types

Even though, Event implements ComponentType and Lift, required for creating Rust types from Wit -Lift's doc: "Host types which can be created from the canonical ABI", the two types cannot be interchanged when converting from wit record to Rust struct. Of course, I can make an impl Into<Event> for host::Event implementation, but it introduces additional complexity to the code, because of nesting in the function's return type. I can go back to working with raw Instance and manually set the exports and imports, but I am sure there is a more elegant approach to using the host bindings.

view this post on Zulip Alex Crichton (May 05 2025 at 15:26):

This may not be implemented yet, but this is partially motivation for the with option to the bindgen! macro. I know that for resources you can specify a custom type, but I don't think we have it set up to specify a custom type for any arbitrary WIT type yet. Adding that in theory wouldn't be too hard though.

view this post on Zulip Bozhidar Manev (May 05 2025 at 15:44):

Then I am curious how manually defining and calling exports with Rust types which comply with trait bounds is working :

// My old approach by only using Rust structs
// type ByteArr = Vec<u8>
    async fn call_execute(
        &mut self,
        cmd: PlatformMessage,
    ) -> Result<Result<Vec<Event>, ByteArr>, wasmtime::Error> {
        self.load_instance(&cmd).await.and_then(|instance| {
            instance
                .get_typed_func::<(ByteArr,), (Result<Vec<Event>, ByteArr>,)>(
                    &mut self.store,
                    "execute",
                )
                .and_then(|func| func.call(&mut self.store, (cmd.payload().to_vec(),)))
                .map(|result| result.0) // getting the data from (A,) to A
        })
    }

Maybe it is all about giving types, which comply with the trait bounds in .get_typed_func and wasmtime handles the type compatibility instead of the Rust compiler when using the host bindings

view this post on Zulip Alex Crichton (May 05 2025 at 15:54):

yeah the types you provide to get_typed_func are what the function ends up actually returning

view this post on Zulip Alex Crichton (May 05 2025 at 15:55):

there's still type-checks and such to make sure everything works out, but that's the part that has to agree

view this post on Zulip Bozhidar Manev (May 05 2025 at 15:59):

Thanks, then I will work with what is available. I am looking forward to seeing such type resolving in the future! If anybody has any workarounds feel free to share


Last updated: Dec 06 2025 at 06:05 UTC