Stream: wit-bindgen

Topic: Best way to share generated types amongst worlds


view this post on Zulip Philpax (Mar 01 2023 at 13:11):

Hi there! I'm working on porting our bindings over to the latest wit-bindgen (cd9d253d115040a8474eba6350340d7491e3183f) and a recent-ish wasmtime (b5e9fb710ba73bde295eec5ab57f6ef4f6459e79, there's a bindgen output discrepancy that I wanted to figure out later), and am sketching out how to best handle code sharing between worlds.

I have a main.wit that defines two worlds:

world client {
    import types: pkg.types

    import component: pkg.component
    import entity: pkg.entity
    import player: pkg.player
    import event: pkg.event

    export guest: pkg.guest
}

world server {
    import types: pkg.types

    import component: pkg.component
    import entity: pkg.entity
    import player: pkg.player
    import physics: pkg.physics
    import event: pkg.event
    import asset: pkg.asset

    export guest: pkg.guest
}

I'm defining two worlds as there's two versions of this API (one for clientside WASM logic, one for serverside WASM logic). However, the interfaces that are shared use the same logic on both the host and the guest - that is, the host implementation for the functions defined in pkg.entity is identical, and the guest would access them the same way.

However, wit-bindgen on the guest and wasmtime's bindgen both require me to specify a world. That means I can't specify both worlds in the same bindgen call, so I'd have to use two separate bindgen calls which would create duplicate non-interoperable types.


What would the best way to share common types while still ensuring that the bits that aren't common aren't dragged in as well?

I was thinking of defining a shared world and moving the commonalities in there, but would I be able to use the types from that world, and would they be compatible? My ideal scenario here is defining my host / guest logic once for the shared functionality, and then defining them separately for the specific per-world functionality.

If all fails, I'll just chuck it all in the same world and use convention with the interface names to delineate what belongs to each domain, but I'd like to avoid that if possible.

view this post on Zulip Alex Crichton (Mar 01 2023 at 15:50):

you might be interested in this feature perhaps, but otherwise the rough intention is that guest programs and hosts are generated with the same world as a world describes a concrete component. Can you say a bit more about why you've got two worlds and how they're going to be used?

I want to raise this issue to propose a new syntax for the union of Worlds. The primary motivation for this proposal is that we want to be able to form a more compresive world by unionizing / combi...

view this post on Zulip Philpax (Mar 01 2023 at 16:47):

That proposal looks great! Will keep an eye on it.

No problem on the clarification. I built out the WASM integration for Ambient, which is a game runtime that loads games powered by WASM on the server; clients can then join the server and receive assets. At present, we have server-side only WASM and I've implemented bindings for that. Our host is in Rust, and our guest is currently also Rust (with some higher-level wrappers around the raw WIT types).

In the near-future, though, we'd like to send WASM to the client and have them run it, too. The API for both the client and the server (will) share a lot of functionality, and I'd like to avoid having to reimplement the common functionality. On the other hand, they also have points of divergence; there's functionality only one of the two sides will have access to.

So one host executable (ambient) can provide export bindings for both the client and server API, depending on which mode it's running on. There can be two guest modules, compiled against the same API crate wrapping WIT types (but with different feature flags to expose the different portions of the API).

That is:

The host in both cases should provide the same entity.set-component implementation, and ideally the guest would use the same path to access it (i.e. so that I don't have to do cfg(feature = "server") use server as wit; etc). However, physics.apply-force wouldn't be available when building guest WASM for client.

Let me know if you need any further clarification, but I'm thinking I'll probably have to use the same world for these at the moment.

The multiplayer game engine. Contribute to AmbientRun/Ambient development by creating an account on GitHub.

view this post on Zulip Alex Crichton (Mar 01 2023 at 20:00):

Where does the sharing become necessary? With two wasm binaries you'd generate one world in each but there's no need to share types since they're separate binaries. Are you thinking the embedder code, though, would conditionally use types from either world?

view this post on Zulip Philpax (Mar 02 2023 at 12:17):

That's right. On the guest side, it would be nice to share types/functions for convenience (so that I can have fn spawn(...) { wit::spawn(...) } without having to alias wit depending on the world), but that can be worked around. The more pressing issue is for the host.

I'd like to avoid reimplementing the interface functions and the code that consumes the WIT types on the host, as that's a lot of duplication for all of the code that interfaces with WIT. e.g. if I have entity.spawn: func(data: list<tuple<u32, component-value>>) -> entity-id for both the client and server worlds, the host would have to reimplement spawn twice, conversion from server.component-value and client.component-value to the host representation, and conversion from the host's entity-id to server.entity-id and client.entity-id(and vice versa) - and this would have to happen for everything that's shared between the worlds.

view this post on Zulip Alex Crichton (Mar 02 2023 at 21:21):

Hm ok, I think it's basically the case that this isn't well supported today. Not to say it can't be, it would require work on the code generators though

view this post on Zulip Philpax (Mar 03 2023 at 09:05):

Yeah, fair enough - I'll see how I go with using a single world, thanks!


Last updated: Oct 23 2024 at 20:03 UTC