I'm trying to use the with
and interfaces
options to wasmtime::component::bindgen!
to share generated code for types in an interface.
I seem to have it working for _imports_ by doing things like this:
pub mod types {
pub mod job_server_api {
wasmtime::component::bindgen!({
path: "wit/",
interfaces: "
import jeffparsons:job-server/job-server-api;
",
});
pub use self::jeffparsons::job_server::job_server_api::*;
}
}
pub mod job_worker {
wasmtime::component::bindgen!({
world: "jeffparsons:job-worker/job-worker",
with: {
"jeffparsons:job-server/job-server-api": crate::types::job_server_api,
},
});
}
But I'm also trying to _export_ an implementation of job-server-api
from the host. (A kind of proxy that dispatches calls to either local or remote components.) I can't figure out how to share the generated code for types in job-server-api
across both imports and exports.
Is this possible somehow? The generated code for the imports and exports appears to be identical (except for borrowing convention in the call_whatever
methods which is not really an issue) so I assume there's nothing morally reprehensible about what I want to do. :sweat_smile:
My workaround for now is to hand-write From
implementations for one or both directions, depending on how the types are used. But that's getting verbose and tedious pretty quickly, as you might imagine. If the generated Rust types can't be the same for some reason, generating these conversions from bindgen!
would also be pretty handy.
Thanks!
I should add that I'm actually thinking of these bindgen!
-generated bindings as a stopgap, and ultimately I'd like to do this generically, i.e. without the host program having hard-coded knowledge of most of those guest components. (Full context: https://bytecodealliance.zulipchat.com/#narrow/stream/223391-wasm/topic/Wasm.20Components.20and.20service-oriented.20architecture)
So if there's some way to achieve this using the dynamic type/value stuff in wasmtime::component::{types, Val}
, LinkerInstance::func_new
, etc. instead then I'd be happy to go down that path instead. I'm just not sure if that's possible. (I'm not familiar with it, don't know what limitations exist).
Also, I don't care much about performance; I don't expect these interfaces to be a bottleneck. So if a super-dynamic approach turns out to be the most ergonomic, that's fine.
The generated types today currently try to reflect what's happening on the WIT level with different types for imports/exports largely, but that doesn't mean this couldn't be unified where possible either. Mind filing an issue for this?
Thanks, can do!
Alex Crichton said:
[...] what's happening on the WIT level with different types for imports/exports [...]
I had a feeling I'd read something vaguely related to that somewhere, but I don't understand why a type as defined on an interface (e.g. record) is considered a different type depending on whether the interface is imported or exported. I'm sure it all makes sense — it's just not obvious to me (yet).
I'll definitely be using the generated bindings for now; even with my hand-coded conversions it's good enough to let me focus on more interesting parts of the project. But eventually I'll want to do all this dynamically, so I guess I'd better crack open some of the generated components to try to understand when I can safely treat types from different components as equal, etc.
Last updated: Dec 23 2024 at 13:07 UTC