-
Notifications
You must be signed in to change notification settings - Fork 92
Description
Hello!
First off, I am not sure if this is the proper place for this issue, as I don't know if this issue is a problem with the component model itself, or if the issue is just with cargo-component. If this is not an issue with the component model / WIT itself, I am happy to move this issue to the appropriate repo.
Since I understand that stream<T>
is still a work in progress, I decided to try to roll my own WIT worlds / interfaces for reactive flows. Since WIT does not currently have first-class functions / callback types, I tried to emulate this via resource types. I did something like:
interface callbacks {
resource s32-update-handler {
on-update: func(value: s32);
}
}
interface reactive-values {
resource s32-reactive-value {
current-value: func() -> s32;
register-update-handler: func(handler: s32-update-handler);
unregister-update-handler: func(handler: s32-update-handler);
}
new-s32-reactive-value: func(initial: s32) -> tuple<s32-update-handler, s32-reactive-value>;
}
world my-world {
export callbacks;
import reactive-values;
}
The callbacks are exported so that the client component can implement the callbacks natively, and the reactive-values are imported, because this is something that should be implemented by the host / another wasm component (to keep the implementation of the reactive values decoupled from the client component).
However, when I try to use this WIT to implement a component with cargo-component, with the following snippet:
let (set_x, x) = new_s32_reactive_value(0);
let (set_y, y) = new_s32_reactive_value(0);
let (set_x_y_sum, x_y_sum) = new_string_reactive_value("0");
x.register_update_handler(S32UpdateHandler::new(IntCallback(Box::new(|x| {
let y = y.current_value();
let sum = (x + y).to_string();
set_x_y_sum.on_update(sum);
}))));
y.register_update_handler(S32UpdateHandler::new(IntCallback(Box::new(|y| {
let x = x.current_value();
let sum = (x + y).to_string();
set_x_y_sum.on_update(&sum);
}))));
I get the error:
mismatched types
`S32UpdateHandler` and `S32UpdateHandler` have similar names, but are actually distinct typesrustc[Click for full compiler diagnostic](rust-analyzer-diagnostics-view:/diagnostic%20message%20[5]?5#file:///Users/nathan/Code/wasm-rust-gui-example/src/lib.rs)
lib.rs(32, 11): arguments to this method are incorrect
bindings.rs(5222, 17): `S32UpdateHandler` is defined in module `crate::bindings::exports::component::wasm_rust_gui_example::update_handlers` of the current crate
bindings.rs(502, 13): `S32UpdateHandler` is defined in module `crate::bindings::component::wasm_rust_gui_example::update_handlers` of the current crate
bindings.rs(1254, 24): method defined here
So it seems to me like cargo-component is generating two separate types for S32UpdateHandler for imported versions of the type, and exported versions of the type, which makes sense to me -- because obviously the implementation is going to be different depending on whether the resource is coming from your component, or from an external component.
However, what I really want is (to make up some syntax for an "imported" and "exported" modality for types:
imported resource s32-reactive-value {
current-value: func() -> s32;
register-update-handler: func(handler: exported s32-update-handler);
unregister-update-handler: func(handler: exported s32-update-handler);
}
In other words, to be able to use callbacks (update handlers) that have been exported from the client within an imported resource type. But since there isn't a way of expressing the "import / export" modality (for lack of a better term) of the types in such a granular way, I am not sure how to accomplish this.
Is it possible to do what I am trying to do here in WIT today and maybe I am just doing things wrong? Do the semantics of imported / exported resources need to be refined / clarified in order to support this kind of use-case?
Note: I can provide a trimmed down minimally reproducible example if needed.