Stream: general

Topic: Creating a Rust crate library that uses WIT


view this post on Zulip Ben McCormick (Oct 27 2023 at 21:01):

Hello,

I've been looking for an example of this behavior, and if one exists, consider this question answered.

I have a custom Rust runtime using wasmtime to run component model apps/plugins, all of which are so far written in Rust as well and use the same WIT file by running cargo_component_bindings::generate!(). What I'd like to do next is create a Rust library crate for all of these apps/plugins to deduplicate the boilerplate code that comes along with various serialization steps and trait implementations for the types defined in my WIT file.

When I try to do this by creating a component and use-ing it in another one, I run into all kinds of issues such as the target/bindings/<package>/target.wasm file being in the wrong place for the 'library' and the component doing the import being seemingly unable to reach code in the other component.

It seems like this might be the wrong strategy to do what I want to do -- is there an idiomatic way to do this kind of thing?

view this post on Zulip Peter Huene (Oct 27 2023 at 21:42):

If you want to create a Rust crate that effectively is a wrapper around your bindings (either to provide a higher-level abstraction or extending the functionality of the binding types themselves), you'll probably want to use wit-bindgen directly from that crate to do so, and then in the component crate, you have it target an empty world and have a normal crate dependency to the bindings crate from your component itself (in theory that should work, but it doesn't have any test coverage)

view this post on Zulip Ben McCormick (Oct 27 2023 at 22:28):

Thank you, but could you clarify how to use wit-bindgen to access the functions that my WIT file exposes as "imports"? I can access the types in my interface, but can't find the functions I want to wrap around.

view this post on Zulip Peter Huene (Oct 27 2023 at 22:33):

it depends on the imports, but generally they'll generate something like ns::name::iface::funcwhen the world imports an interface ns:name/iface and something like world::func when the world imports a function. i forget the exact paths off the top of my head

view this post on Zulip Peter Huene (Oct 27 2023 at 22:33):

i also find using cargo-expand to see exactly what the generated bindings were helps a little

view this post on Zulip Peter Huene (Oct 27 2023 at 22:33):

i have to run and will be back online later

view this post on Zulip Ben McCormick (Oct 27 2023 at 22:37):

Okay, thanks! I'll try cargo expand

view this post on Zulip Ben McCormick (Oct 27 2023 at 23:41):

Okay, I've been able to do this strategy successfully now for importing the wrapper and using it in a component. I think it's very close to working, I just have one last problem: Since my wrapper runs wit_bindgen::generate!, it won't compile unless I handle the exports and impl Guest for Component.

Then, even though I can impl Guest again in my component that uses the "wrapper", the impl in the wrapper gets used when I use the compiled app in my runtime. Can I set the wrapper up such that it doesn't have to create the Guest, or set up the component so that its Guest gets used in the final thing?

view this post on Zulip Ben McCormick (Nov 01 2023 at 21:31):

I should clarify that I'm using wasmtime as the runtime for these WASM plugins -- so the runtime is using the generate! macro in wasmtime::component, but the "library" is using wit_bindgen::generate!. This seems to be fine in the sense that I can get the library to execute just fine inside the runtime. I think I just need a way to overwrite the impl inside the "library" when I import it into a plugin.

view this post on Zulip Jeff Parsons (Nov 02 2023 at 00:29):

I have a similar (but I think slightly different) use case: I'd like to generate code just for my common WIT types into a shared Rust crate so that I can attach behaviour to them. I'd then want to have several component crates, all with their own worlds, using that shared crate.

Am I right in thinking that wit-bindgen would need to learn some new tricks for this to work? Namely: filter what wit namespaces to generate code for, and also tell it where to find pre-generated code for a given namespace?

Is this something that is already on anyone's radar? If I wanted to have a think about what this might look like, should I open an issue on the wit-bindgen repo with some examples, or better to post it to zulip?

view this post on Zulip Pat Hickey (Nov 02 2023 at 00:32):

yes, this feature for wit-bindgen landed recently by roman and brian https://github.com/bytecodealliance/wit-bindgen/pull/699

Closes #694 Introduce with Rust macro argument supported by Wasmtime bindgen. Big part of this is adapted from Wasmtime source code. The implementation is very simple and has minimal changes to exi...

view this post on Zulip Jeff Parsons (Nov 02 2023 at 00:44):

Oh, cool! I'll definitely give this a go. Thanks! :sparkling_heart:

view this post on Zulip Karel Hrkal (kajacx) (Jan 02 2024 at 11:38):

A late response, but I have solved this exact issue by making a rust library that "wraps" the native wit bindgen generated types, adding useful functions, deriving more traits, etc. The individual plugins can then depend on this library and have a much nicer API to work with than if they used the wit bindings directly.

The library I created for this in one of my projects is here, although the code is a bit outdated and would require some changes to update it to the newest version of wit bindgen.


Last updated: Dec 23 2024 at 12:05 UTC