Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared types in back-and-forth communication between the host and the protocol #37

Open
kajacx opened this issue Mar 29, 2023 · 2 comments

Comments

@kajacx
Copy link

kajacx commented Mar 29, 2023

Backstory
I want to use WAI to create a plugin system, where I define the host protocol, implemented by the host, and the plugin protocol, implemented by the plugin. The host will call functions implemented by the plugin, and the plugin can call functions implemented by the host.

I have a working example in this repo, both with wasmer runtime, and wasmtime runtime.

The problem

When I want to use a custom type, like vector3f in this example, I have to define it in both the host protocol, and in the plugin protocol.

Host protocol:

move-y: func(vec: vector3f) -> vector3f

record vector3f {
  x: float32,
  y: float32,
  z: float32,
}

Plugin protocol:

move-vec: func(vec: vector3f) -> vector3f

record vector3f {
  x: float32,
  y: float32,
  z: float32,
}

This works, but if I want to call the moveY host function from the moveVec plugin function with the same Vector3f type, I quickly run into a problem: it's not the same Vector3f type!

Current solution / workaround

Currently I am solving this by manually converting the host Vector3f type to the plugin one and back, like so:

    fn move_vec(vec: sample_protocol_plugin::Vector3f) -> sample_protocol_plugin::Vector3f {
        let mut as_host = sample_protocol_host::Vector3f {
            x: vec.x,
            y: vec.y,
            z: vec.z,
        };

        as_host.x += 1.0;

        as_host = move_y(as_host);

        as_host.z += 1.0;

        sample_protocol_plugin::Vector3f {
            x: as_host.x,
            y: as_host.y,
            z: as_host.z,
        }
    }

Needless to say, this is not ideal. Even if the implementation of the conversion could be generated by a macro, I would still need to call ::from() and .into() and worry about which type is which.

Solutions?

This would probably need a separate types.wai file with just the types definitions, then a macro to just import the types from this file, and then finally a way for the import! and export! macros to use the type definitions generated by the previous type macro, instead of generating their own.

Not sure if WAI bindgen supports this, but it would be cool if it did. Any other suggestions on how to (more) easily exchange the same type between host and plugin back and forth are welcome.

@lanastara
Copy link

lanastara commented Jul 19, 2023

In general the ability to use things from the imports inside the exports and the other way around would be really useful.

For example I want to write a Plug-in system. Usually you'd have an init method that registers all it's functionality to a central registry.

So the init method gets defined in exports so far so good but how am I supposed to get the registry. I can't add it as a parameter because the type doesn't exist in the wai file. If I add an import a method that returns the registry then I can only use types defined in the import wai file so I can't use for example resources defined in the export.

No matter what I do I end up needing to use either things from the import side in the export sice or the other way around.

@kajacx
Copy link
Author

kajacx commented Jul 19, 2023

@lanastara you can have a look at the wit format, but that is using wasmtime instead of wasmer.

You also need to use wasmtime's compoent model, and there is not a lot of documentation, but it works well if you get it going.

You can define type, imports and exports in a single wit file and even compose multiple wit files together.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants