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

Reprise: Ability to turn a JsValue to/from an i32 #1766

Open
icefoxen opened this issue Sep 12, 2019 · 5 comments
Open

Reprise: Ability to turn a JsValue to/from an i32 #1766

icefoxen opened this issue Sep 12, 2019 · 5 comments

Comments

@icefoxen
Copy link

Motivation

This was talked about in #999 but that was nearly a year ago so I wanted to see how people's thoughts on the matter have changed, if at all. Essentially, https://github.com/rust-windowing/raw-window-handle wants to solve the problem of version breaking between windowing implementations and graphics libraries by adding a layer of indirection that can be represented as primitive types such as integers or pointers. As it is, if a graphics library is designed to work with a JsValue from wasm-bindgen 0.2.49 and a windowing system insists on one from wasm-bindgen 0.2.48, there's absolutely zero ways to really make them cooperate, even if nothing about the JsValue or how they work has changed between versions.

This is a real and persistent problem: gfx-hal 0.2's DX12 backend relies on Winit 0.19, so if you're using gfx-hal 0.2 you're going to be using winit 0.19, and that's that unless you write your own windowing code. If you're using gfx-hal 0.3 you're going to be still using winit 0.19 even when winit 0.20 gets released; you can't use any of the 0.20 release candidates, and when winit 0.20 gets released it will require a breaking change for gfx-hal to also be released. But, if winit exposes types that raw-window-handle can work with, and raw-window-handle exposes types that gfx-hal can work with, then it breaks the link tying gfx-hal and winit to specific versions of each other.

This solution is similar to how the mint crate provides interoperability between vector math libraries, so libraries like ggez don't tie their users to a particular version of nalgebra or cgmath. It basically solves helps the problem of different crates moving at different speeds, since no matter what else the API binding them together moves at the speed of the interoperability crate, which is intended to be pretty stable.

Proposed Solution

So, anyway. This is a long-winded way of saying "it would be useful if we could turn a JsValue into a raw handle of some kind that doesn't depend on a particular version of wasm-bindgen, even unsafely".

Alternatives

raw-window-handle could expose handles based on the version of wasm-bindgen, such as WasmHandle02(JsValue), WasmHandle03(JsValue), and so on, and use feature flags to offer the right ones at compile time. It would work. But it would kinda suck.

The root problem is really that raw-window-handle goes for its portability by handing out the OS's underlying types, which are all either pointers and integers. And it's hard for an API to get more stable than Windows and X11's basic windowing junk. Wasm is a much younger system, and still evolving.

@Pauan
Copy link
Contributor

Pauan commented Sep 12, 2019

JsValue is already just a raw pointer (specifically a u32), and it's pretty much always been that way. So exposing that in an unsafe fashion wouldn't be difficult.

But I think you'll still run into difficulties with version mismatches, because the real problem is all the glue code.

The #[wasm_bindgen] macro inserts a lot of glue code at compile-time, and there's additional glue code inserted by wasm-bindgen-cli. And that glue code can vary from one version of wasm-bindgen to another.

For example, here is a list of the type descriptors that can be sent to JS. This is in the wasm-bindgen crate.

As the comment suggests, there is a corresponding list in the wasm-bindgen-cli crate.

These two lists must be kept in sync, or else you will get extremely bizarre errors at build-time. This is the primary reason why your wasm-bindgen and wasm-bindgen-cli versions must match exactly (though there's other reasons as well).

The reason why the lists might get out of sync is because wasm-bindgen might add a new type which can be passed to JS, so both lists need to be updated.

Do you think exposing a JsValue -> u32 method would be helpful, even given the fact that the glue code can break between versions of wasm-bindgen?

@icefoxen
Copy link
Author

Yeah it looked like the argument in the previous issue for not exposing the u32 directly was that it might change in unportable ways in the future. I'm fine with that since I'd just consider it an API breaking change and get handled as that, since the goal isn't to be able to mix wasm-bindgen 0.2 code with wasm-bindgen 0.3 code, just to make it so as few people as possible have to care what version it actually is. On the other hand, I definitely see where it might cause Weird Issues that are hard to discover, and so it's a question of whether wasm-bindgen (and raw-window-handle for that matter) want to deal with that possibility.

So, speaking as someone who isn't a maintainer in either project, but just an interested observer who wants to use them... I think exposing JsValue -> u32 would be a good place to start, and if it turns out to be a bad choice we will have more information on what a good choice should look like.

@alexcrichton
Copy link
Contributor

Thanks for the report! In addition to what's already been said I'll also link to my previous thoughts about how we want to retain flexibility in what JsValue looks like internally, so we're not ready yet to commit to a u32.

It may be easiest here to basically just consider wasm an exempt target from the crate's semver policy, since wasm in general is just far more unstable than all other platforms.

@RSSchermer
Copy link
Contributor

Just stumbled across this issue, figured I'd remark that #999 is still an active problem for me. Here's what I've been using as stopgap.

@DylanRJohnston
Copy link

Thanks for the workaround @RSSchermer, I needed this to replicate the ability to use JS Objects as Map keys like you can in Javascript.

let map = new Map()

let key1 = {};
let key2 = {};

map.set(key1, "foo")
map.set(key2, "foo")

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

No branches or pull requests

5 participants