I have a WIT component/package called lyra:api
, it has an interface named ecs
. I want to include a resource inside the ecs
interface and use it in another component.
package lyra:api;
// ecs.wit is adjacent to this .wit file
world imports {
// defines resource ecs-world
import ecs;
}
Then I have this component:
package component:witguest;
/// An example world for the component to target.
world example {
import math;
include lyra:api/ecs;
export on-update: func(game-world: ecs-world) -> result;
}
When I run cargo component build
, I get this error:
error: failed to create a target world for package `witguest` (/media/data_drive/Development/Rust/lyra-wasm-scripting-test/witguest/Cargo.toml)
Caused by:
0: failed to parse local target from directory `/media/data_drive/Development/Rust/lyra-wasm-scripting-test/witguest/wit`
1: name `ecs-world` is not defined
--> /media/data_drive/Development/Rust/lyra-wasm-scripting-test/witguest/wit/world.wit:21:40
|
21 | export on-update: func(game-world: ecs-world) -> result;
| ^--------
If you're wondering more about what my project structure is, here's the git repo but it doesn't have these changes in it (I can push them to another branch).
i think you need a use lyra:api/imports.{ecs-world};
in your world example
.
the include
keyword means that all of the imports and exports in the lyre:api/ecs
world will be imported/exported in your example world, but it doesnt bring those names into scope - only use
does that.
Yup that was it! I spent way too long on this and it was so simple lol, thanks!
happy to help. this is a situation where, if we had amazing error messages like rustc, it would just tell you what to do here
oh yeah, better errors would be amazing
I think better docs and examples would be great as well
which docs and examples did you use so far?
I was looking at the docs here: https://component-model.bytecodealliance.org/design/wit.html
I see where use
is explained, but it doesn't show that you also use that to use things from other packages
Other than the examples there, I've also been looking at the examples on the wit-bindgen readme.
yeah i think the whole section on packages on that doc could be expanded to show a bunch more
Okay, so now I'm actually running into a more complicated issue...
So my plan for this project is to integrate WASM as a scripting language in a game engine. Currently I'm just starting with exposing the ECS (Entity Component System) to WASM. That requires exposing some kind of low level interfaces that include passing a vec<u8>
of byte serialized components to and from the host alongside information detailing what those bytes are.
Because I don't want to always deal with manually (de)serializing those bytes to and from the host every time I want to get something from the ECS world, I planned on making a higher level crate that makes it nicer.
In the git repo I sent above, the higher level crate is a wasm component and called common-api
. This crate is a dependency of the witguest
wasm component
This is the witguest
component world:
world example {
import math;
use lyra:api/ecs.{ecs-world};
import host-print: func(msg: string);
export on-init: func() -> result;
export on-update: func(game-world: ecs-world) -> result;
}
ecs-world
is imported
in the common-api crate (lyra:api component) but cargo-component through bindings are generating separate structs of the same name of EcsWorld
, causing that witguest
component not able to use the abstractions of common-api
fn on_update(game_world: EcsWorld) -> Result<(), ()> {
let world = World::from(game_world);
println!("Guest update");
Ok(())
}
error[E0277]: the trait bound `World: From<bindings::lyra::api::ecs::EcsWorld>` is not satisfied
--> witguest/src/lib.rs:36:21
|
36 | let world = World::from(game_world);
| ^^^^^ the trait `From<bindings::lyra::api::ecs::EcsWorld>` is not implemented for `World`
|
= help: the trait `From<common_api::bindings::lyra::api::ecs::EcsWorld>` is implemented for `World`
= help: for that trait implementation, expected `common_api::bindings::lyra::api::ecs::EcsWorld`, found `bindings::lyra::api::ecs::EcsWorld`
have you taken a look at the way that wasmtime-wasi-http
reuses interfaces from the wasmtime-wasi
crate?
Ohh, no I have not. I'll take a look at that
oh, wait, you re talking about on the guest side.
Yeah
I'm basically trying to create a high-level crate for making it easier to use imported interfaces that the host defines. But then the guest still needs to export some functions for the host to call which also passes those low level interfaces that need to be "raised" to the higher-level ones
i dont usually use cargo-component, which invokes wit-bindgen on the users behalf, but the mechanism wit-bindgen exposes for this is the with:
clause in the generate macro: https://docs.rs/wit-bindgen/latest/wit_bindgen/macro.generate.html
i cant link to the right section in the docs, there, you have to scroll down to the comments on with:
in the final section
Ohhh I see it
When generating bindings for interfaces that are not defined in the same package as
world
, this option can be used to either generate those bindings or point to already generated bindings.
Okay that seems like that is actually perfect since I also have the common-api crate as a dependency in cargo
I'll try that rq
yeah its designed for this use case
Okay I'm doing something wrong, but I'm not sure what as the docs don't explain the examples they give. This is what I'm trying in the witguest
component:
wit_bindgen::generate!({
world: "example",
with: {
"lyra:api/ecs": common_api::bindings::lyra::api::ecs,
},
});
But when trying to compile, its not able to find the lyra:api/ecs
package:
package not found
--> /media/data_drive/Development/Rust/lyra-wasm-scripting-test/witguest/wit/world.wit:15:9
|
15 | use lyra:api/ecs.{ecs-world};
| ^-------
I tried to change that with to "lyra:api": common_api::bindings::lyra::api
but that didn't work either, it gave the same error
Pat Hickey said:
yeah i think the whole section on packages on that doc could be expanded to show a bunch more
Generally, in all past versions of such "component [object] models" shall we say, there arose instantly the question of creating shared versions of types that each side used such that each side of an interaction did not need to think of differently named but identical types.
We need to take that as a standalone subject in the docs; tons and tons of threads on the zulip are quitely literally about why is the type different? how do I reuse the same type? and so on...
Last updated: Dec 23 2024 at 13:07 UTC