Stream: git-wasmtime

Topic: wasmtime / issue #11287 `bindgen!` for worlds that use re...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 20 2025 at 17:32):

AmitPr opened issue #11287:

Hey folks, I was wondering whether I'm approaching this wrong, or whether this is an oversight in how wasmtime::component::bindgen! works:

I'm trying to write a WIT interface that allows me to return wasi:keyvalue buckets. Specifically:

package amitpr:test
interface root-store {
    use store.{bucket, error};
    /// Open the root KV store
    open-root: func(identifier: string) -> result<bucket, error>;
}

world sudo {
    import root-store;
}

I then bindgen something like this:

wasmtime::component::bindgen!({
        path: "wit",
        world: "amitpr:test/sudo",
        trappable_imports: true,
        with: {
            "wasi:keyvalue/store/bucket": crate::kv::bucket::MyBucket,
        },
        trappable_error_type: {
            "wasi:keyvalue/store/error" => crate::kv::KVError,
        },
    });

The important thing to note, is that I already have wasi:keyvalue implemented elsewhere, which uses wasi:keyvalue/imports and implements the Host trait for those worlds.

However, when I want to create a Host implementation for this sudo world, my struct is required to be sudo::root_store::Host _as well as_ wasi::keyvalue::store::Host:

struct KvLibrary;
impl HasData for KvLibrary {
    type Data<'a> = KvView<'a>;
}

struct SudoLibrary;
impl HasData for SudoLibrary {
    type Data<'a> = SudoView<'a>;
}

// Later:
        // This works:
        kv::store::add_to_linker::<_, KvLibrary>(&mut linker, kv_getter)?;
        kv::atomics::add_to_linker::<_, KvLibrary>(&mut linker, kv_getter)?;
        kv::batch::add_to_linker::<_, KvLibrary>(&mut linker, kv_getter)?;
        // This tells me that SudoLibrary needs to implement keyvalue Host!
        sudo::add_to_linker::<_, SudoLibrary>(&mut linker, sudo_getter)?;

I'm not 100% sure in what to do in this situation. Of course, I could duplicate the wasi:keyvalue host trait implementation, but that seems super unidiomatic. Am I missing why my SudoLibrary is enforced to implement the wasi:keyvalue worlds? Is there a way for me to invoke the macro without that bound, since wasi:keyvalue will already have bindings in my instantiation of the linker? Or is there a way for me to more idiomatically include the wasi:keyvalue host implementation in the SudoView struct I have?

Thanks

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2025 at 16:16):

pchickey commented on issue #11287:

I believe this can be fixed if the sudo world's with clause contains a mapping for the entire wasi:keyvalue/store interface to the generated bindings module for that interface, in addition to providing a mapping for the resource. You may be able to elide the mapping for the resource, but I'm not certain.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2025 at 19:21):

alexcrichton commented on issue #11287:

You might also need to use the per-interface add_to_linker instead of a top-level add_to_linker if you're using different data/projections for each of the *_getter functions.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2025 at 19:21):

alexcrichton added the wasmtime:api label to Issue #11287.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2025 at 19:21):

alexcrichton added the wasm-proposal:component-model label to Issue #11287.

view this post on Zulip Wasmtime GitHub notifications bot (Aug 08 2025 at 18:24):

AmitPr commented on issue #11287:

@pchickey this worked, but specifying the entire interface to another set of bindings seems like a somewhat flimsy way to set things up.

Not sure if this can be improved, to allow for the situation where there may be bindings in e.g. private modules. Perhaps this is addressed by eliding the mapping? Although I'm not sure how you would accomplish that.

Leaving this open, but feel free to close if status quo is alright

view this post on Zulip Wasmtime GitHub notifications bot (Aug 08 2025 at 22:24):

pchickey commented on issue #11287:

Sorry, I didn't elaborate much. This should only take a single line in with pointing to a public module in another crate.

The module with reusable bindings has to be public to be used from another crate, I don't think theres any way to get around that).

From my own project (sorry, no source link available at this time) which uses the wasmtime-wasi-io crate to implement wasi:io, and provides its own impls of the rest of the wasi interfaces (or any other wits which use any aspect of wasi:io):

wasmtime::component::bindgen!({
    world: "my:embedding/bindings",
    exports: {
        default: async,
    },
    imports: {
        default: trappable,
    },
    with: {
        // delegate wasi-io implementation to wasmtime-wasi-io:
        "wasi:io": wasmtime_wasi_io::bindings::wasi::io,
        // Then, the rest of the definitions which are local to this crate:
        "wasi:http/types/incoming-request": http::IncomingRequestResource,
        // ...snip
    },
    // This flag is required for compatibility with wasmtime-wasi-io:
    require_store_data_send: true,
});

view this post on Zulip Wasmtime GitHub notifications bot (Aug 08 2025 at 22:25):

pchickey edited a comment on issue #11287:

Sorry, I didn't elaborate much. This should only take a single line in with pointing to a public module in another crate.

The module with reusable bindings has to be public to be used from another crate, I don't think theres any way to get around that).

From my own project (sorry, no source link available at this time) which uses the wasmtime-wasi-io crate to implement wasi:io, and provides its own impls of the rest of the wasi interfaces (or any other wits which use any aspect of wasi:io):

wasmtime::component::bindgen!({
    world: "my:embedding/bindings",
    exports: {
        default: async,
    },
    imports: {
        default: trappable,
    },
    with: {
        // delegate wasi-io implementation to wasmtime-wasi-io:
        "wasi:io": wasmtime_wasi_io::bindings::wasi::io,
        // Then, the rest of the definitions which are local to this crate:
        "wasi:http/types/incoming-request": http::IncomingRequestResource,
        // ...snip
    },
    // This flag is required for compatibility with wasmtime-wasi-io:
    require_store_data_send: true,
});

Does this technique feel less flimsy than what you did?

view this post on Zulip Wasmtime GitHub notifications bot (Aug 08 2025 at 22:25):

pchickey edited a comment on issue #11287:

Sorry, I didn't elaborate much. This should only take a single line in with pointing to a public module in another crate.

The module with reusable bindings has to be public to be used from another crate, I don't think theres any way to get around that.

From my own project (sorry, no source link available at this time) which uses the wasmtime-wasi-io crate to implement wasi:io, and provides its own impls of the rest of the wasi interfaces (or any other wits which use any aspect of wasi:io):

wasmtime::component::bindgen!({
    world: "my:embedding/bindings",
    exports: {
        default: async,
    },
    imports: {
        default: trappable,
    },
    with: {
        // delegate wasi-io implementation to wasmtime-wasi-io:
        "wasi:io": wasmtime_wasi_io::bindings::wasi::io,
        // Then, the rest of the definitions which are local to this crate:
        "wasi:http/types/incoming-request": http::IncomingRequestResource,
        // ...snip
    },
    // This flag is required for compatibility with wasmtime-wasi-io:
    require_store_data_send: true,
});

Does this technique feel less flimsy than what you did?

view this post on Zulip Wasmtime GitHub notifications bot (Aug 28 2025 at 15:18):

AmitPr closed issue #11287:

Hey folks, I was wondering whether I'm approaching this wrong, or whether this is an oversight in how wasmtime::component::bindgen! works:

I'm trying to write a WIT interface that allows me to return wasi:keyvalue buckets. Specifically:

package amitpr:test
interface root-store {
    use store.{bucket, error};
    /// Open the root KV store
    open-root: func(identifier: string) -> result<bucket, error>;
}

world sudo {
    import root-store;
}

I then bindgen something like this:

wasmtime::component::bindgen!({
        path: "wit",
        world: "amitpr:test/sudo",
        trappable_imports: true,
        with: {
            "wasi:keyvalue/store/bucket": crate::kv::bucket::MyBucket,
        },
        trappable_error_type: {
            "wasi:keyvalue/store/error" => crate::kv::KVError,
        },
    });

The important thing to note, is that I already have wasi:keyvalue implemented elsewhere, which uses wasi:keyvalue/imports and implements the Host trait for those worlds.

However, when I want to create a Host implementation for this sudo world, my struct is required to be sudo::root_store::Host _as well as_ wasi::keyvalue::store::Host:

struct KvLibrary;
impl HasData for KvLibrary {
    type Data<'a> = KvView<'a>;
}

struct SudoLibrary;
impl HasData for SudoLibrary {
    type Data<'a> = SudoView<'a>;
}

// Later:
        // This works:
        kv::store::add_to_linker::<_, KvLibrary>(&mut linker, kv_getter)?;
        kv::atomics::add_to_linker::<_, KvLibrary>(&mut linker, kv_getter)?;
        kv::batch::add_to_linker::<_, KvLibrary>(&mut linker, kv_getter)?;
        // This tells me that SudoLibrary needs to implement keyvalue Host!
        sudo::add_to_linker::<_, SudoLibrary>(&mut linker, sudo_getter)?;

I'm not 100% sure in what to do in this situation. Of course, I could duplicate the wasi:keyvalue host trait implementation, but that seems super unidiomatic. Am I missing why my SudoLibrary is enforced to implement the wasi:keyvalue worlds? Is there a way for me to invoke the macro without that bound, since wasi:keyvalue will already have bindings in my instantiation of the linker? Or is there a way for me to more idiomatically include the wasi:keyvalue host implementation in the SudoView struct I have?

Thanks

view this post on Zulip Wasmtime GitHub notifications bot (Aug 28 2025 at 15:18):

AmitPr commented on issue #11287:

Going to go ahead and close this; I think @pchickey’s technique works well and doesn’t feel much like a hack anymore!

Thanks folks


Last updated: Dec 06 2025 at 06:05 UTC