Stream: general

Topic: Including types from other components/packages


view this post on Zulip SeanOMik (Jul 25 2024 at 23:22):

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).

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:28):

i think you need a use lyra:api/imports.{ecs-world};

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:29):

in your world example.

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:30):

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.

view this post on Zulip SeanOMik (Jul 25 2024 at 23:32):

Yup that was it! I spent way too long on this and it was so simple lol, thanks!

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:33):

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

view this post on Zulip SeanOMik (Jul 25 2024 at 23:34):

oh yeah, better errors would be amazing

view this post on Zulip SeanOMik (Jul 25 2024 at 23:34):

I think better docs and examples would be great as well

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:34):

which docs and examples did you use so far?

view this post on Zulip SeanOMik (Jul 25 2024 at 23:35):

I was looking at the docs here: https://component-model.bytecodealliance.org/design/wit.html

view this post on Zulip SeanOMik (Jul 25 2024 at 23:35):

I see where use is explained, but it doesn't show that you also use that to use things from other packages

view this post on Zulip SeanOMik (Jul 25 2024 at 23:36):

Other than the examples there, I've also been looking at the examples on the wit-bindgen readme.

A language binding generator for WebAssembly interface types - bytecodealliance/wit-bindgen

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:37):

yeah i think the whole section on packages on that doc could be expanded to show a bunch more

view this post on Zulip SeanOMik (Jul 25 2024 at 23:38):

Okay, so now I'm actually running into a more complicated issue...

view this post on Zulip SeanOMik (Jul 25 2024 at 23:41):

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.

view this post on Zulip SeanOMik (Jul 25 2024 at 23:42):

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

view this post on Zulip SeanOMik (Jul 25 2024 at 23:44):

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

view this post on Zulip SeanOMik (Jul 25 2024 at 23:44):

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`

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:45):

have you taken a look at the way that wasmtime-wasi-http reuses interfaces from the wasmtime-wasi crate?

view this post on Zulip SeanOMik (Jul 25 2024 at 23:46):

Ohh, no I have not. I'll take a look at that

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:46):

oh, wait, you re talking about on the guest side.

view this post on Zulip SeanOMik (Jul 25 2024 at 23:46):

Yeah

view this post on Zulip SeanOMik (Jul 25 2024 at 23:49):

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

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:49):

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

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:49):

i cant link to the right section in the docs, there, you have to scroll down to the comments on with:

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:49):

in the final section

view this post on Zulip SeanOMik (Jul 25 2024 at 23:50):

Ohhh I see it

view this post on Zulip SeanOMik (Jul 25 2024 at 23:50):

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.

view this post on Zulip SeanOMik (Jul 25 2024 at 23:50):

Okay that seems like that is actually perfect since I also have the common-api crate as a dependency in cargo

view this post on Zulip SeanOMik (Jul 25 2024 at 23:51):

I'll try that rq

view this post on Zulip Pat Hickey (Jul 25 2024 at 23:51):

yeah its designed for this use case

view this post on Zulip SeanOMik (Jul 26 2024 at 00:02):

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};
             |         ^-------

view this post on Zulip SeanOMik (Jul 26 2024 at 00:03):

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

view this post on Zulip Ralph (Jul 26 2024 at 11:58):

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.

view this post on Zulip Ralph (Jul 26 2024 at 11:58):

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: Nov 22 2024 at 16:03 UTC