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

Wasm support (non-javascript environments) #658

Open
coderedart opened this issue May 20, 2024 · 0 comments
Open

Wasm support (non-javascript environments) #658

coderedart opened this issue May 20, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@coderedart
Copy link

coderedart commented May 20, 2024

Note: For Javascript (in web or node/deno), there's #241 . This issue is about wasm on non-js environments like wasmtime/wasmer and requires a completely different approach (as wasm_bindgen is not available here).

What problem does this solve or what need does it fill?

Taffy is used for UI. For any application that wants to support "scripting"/"modding" (eg: bevy games or text editors like lapce ), its necessary that the plugins get to display their own UI. And it also means that they might want to interact with the layout of the widgets on the host side. eg: creating a button widget and changing its text size.

We can do this in two ways:

C FFI

By default, wasm only supports primitives (ints and floats) and cannot read/write to host memory. So, we will need a C FFI API that is exposed by platforms like windows.

// for primitives as arguments or return values, its obvious
unsafe fn get_width() -> i32;
unsafe fn set_width(value: i32);
// for dealing with host side objects, we need to use pointers to opaque objects as we can't read/write that memory and only use the pointers with pre-exposed FFI functions.
struct opaque_button_type;
unsafe fn button_new() ->  * mut opaque_button_type;
unsafe fn button_destroy(button:  * mut opaque_button_type);

// and finally when we need to deal with concrete POD (plain old data) c struct types, we will need to take care of allocating them on guest side and then call a ffi function, which will then read the data from that pointer.
#[repr(C)]
pub struct Point {
	pub x: f32,
	pub y: f32
}
// unsafe fn button_get_pos(button: * const opaque_button_type) -> Point; !!! won't work. only primitives

// Instead, you allocate a mut point on stack or heap, and pass the [mut] ptr to the above function.
unsafe fn button_get_pos(button: *const opaque_button_type, point: * mut Point); // written to by host
unsafe fn button_set_pos(button: *mut opaque_button_type, point: * const  Point); // read by host.

Component Model

This is unstable, but you will write the types used by taffy in a wit world (using wit syntax which is almost rust anyway).

copying example from wit-bindge's README

package example:my-game;

interface my-plugin-api {
  record coord {
    x: u32,
    y: u32,
  }
  // the wasm runtime will take care of translating the serializeable data types between native host and guest wasm.
  // we just need to implement some traits generated by wit-bindgen's "bindgen!" macro.
  get-position: func() -> coord;
  set-position: func(pos: coord);

  record monster {
    name: string, // also supports complex types like strings or option/results etc..
    hp: u32,
    pos: coord,
  }

  monsters: func() -> list<monster>
  // for dealing with host side types like button widget or host side taffy struct, we will still have to use refs (wasm pointers) and a c like getter/setter API
}

This might replace #241 in the nearby future.
And may even be helpful in #617
But, like I said, its not stable. And it doesn't change the fact that it still requires a C like API for dealing with host side objects (eg: opaque_button_type) using extern refs.

What solution would you like?

I think its better to go with the C API which is useful for both wasm and native bindings. But, we still need to wrap the unsafe C API into idiomatic safe APIs for the respective language.
This means, we will need to wrap the unsafe C api with a new safe rust API, just like we do for C libraries. Then, we will use dynamic linking (as the host will provide the actual implementations for those functions).

This will also be useful for distributing taffy as a dll, used by rust or other languages like python(PyO3 module)/java/nodejs (napi module)/deno via FFI.

What alternative(s) have you considered?

If we had #440 , plugins can use serialize/deserialization to just use raw CSS strings directly. It still won't be ideal though, because now we need to think of how to apply which css to which widget (class, id etc..) and the order of overrides etc..

Additional context

There's projects like https://github.com/getditto/safer_ffi which have convenience macros for C bindings. Although, the macros might increase compile times.

@coderedart coderedart added the enhancement New feature or request label May 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant