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

Web support via stdweb and web-sys #26

Merged
merged 6 commits into from
Sep 26, 2019
Merged

Web support via stdweb and web-sys #26

merged 6 commits into from
Sep 26, 2019

Conversation

ryanisaacg
Copy link
Contributor

@ryanisaacg ryanisaacg commented Sep 3, 2019

Old PR:
This will probably not be the final change, because it:

  • A) will probably require bikeshedding as to the proper way to choose between stdweb / web-sys at compile time
  • B) does not implement 'empty'
  • C) most importantly, removes 'Copy' from the public API of the RawWindowHandle

Some aspect of web support does need to make it into raw-window-handle for web support in winit, but I wanted to put up this PR to start discussion on what that should look like.

Edit: For more context, the Canvas objects in stdweb and web-sys are Clone but not copy, so a struct containing them may not be Copy either. I'm not sure of the best-practice way to work around this.


New PR:

A backend-agnostic numerical ID for web has been added as an option to the window handle enum, with documentation referring users to custom data attributes on HTML elements.

@ryanisaacg ryanisaacg changed the title Do the initial work for web support Web support via stdweb and web-sys Sep 3, 2019
Copy link
Contributor

@Osspial Osspial left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I've added comments where I think changes should be considered, but I'm excited to get support for this.

src/lib.rs Outdated
@@ -46,7 +46,10 @@ pub mod windows;
#[cfg_attr(feature = "nightly-docs", doc(cfg(target_os = "ios")))]
#[cfg_attr(not(feature = "nightly-docs"), cfg(target_os = "ios"))]
pub mod ios;
// pub mod wasm;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There shouldn't be a line break here for consistency reasons.

src/web.rs Outdated
#[cfg(feature = "web-sys")]
pub canvas: web_sys::HtmlCanvasElement,
#[cfg(feature = "stdweb")]
pub canvas: stdweb::web::html_element::CanvasElement,
Copy link
Contributor

@Osspial Osspial Sep 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like this design for conditionally selecting the canvas type. APIs that behave differently should look different, and overloading the canvas name will make this type significantly harder to use, understand, and document.

Ideally we can follow the same approach we use for selecting the X11/Wayland backend: have different variants in the top-level enum for each backend (assuming we don't switch the HTMLCanvasElement representation we're exposing). That being said, I assume there's a reason you made this design choice over the one I just outlined - is there any technical reason why that's a bad idea?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning was 'Winit and X11 are both valid choices in the same binary, but stdweb and web-sys are not.' With that in mind, if they should still be separate I have no problem separating them.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sympathize but since they're not actually the same API, as a user I would prefer that they be entirely different things in the struct.

src/web.rs Show resolved Hide resolved
Cargo.toml Outdated
[target.'cfg(target_arch = "wasm32")'.dependencies.stdweb]
version = "0.4.18"
optional = true

Copy link
Contributor

@Osspial Osspial Sep 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely comfortable with re-exporting these types in our public API, since it opens us up for breaking changes if the downupstream crates ever bump their major version.

Looking at the stdweb source code, it looks like the Canvas struct just wraps around an i32 that specifies the HTMLCanvasElement JS object. Could we expose that i32 instead of the higher-level wrappers, than have downstream users reconstruct the object from that integer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try to look into ways to remove the stdweb and web-sys types from the public API, which should also possibly help with my problem that they aren't 'Copy'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would using Box::into_raw and Box::from_raw on the canvas objects make sense as a design? Then the handle can just be a void*.

The downside is a serious loss of safety, but the upside is that it's more in line with the rest of the API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ryanisaacg I'm not entirely comfortable with doing that, since it seems like an unnecessary layer of indirection over exposing the JS reference integer directly.

stdweb's Reference type exposes unsafe from_raw_unchecked methods for internal use. Could we see about exposing those methods in the public API? From a light investigation it seems the main reason they aren't exposed is because the authors didn't think there was much reason to expose them (based on koute/stdweb#339), but I think we've got an acceptable reason here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll propose upstream methods to stdweb and wasm-bindgen to have unsafe methods for converting back and forth between the integer ID's.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting ourselves up for either a breaking change or forcing our users to use legacy code would fundamentally undermine the stability and common ground that this library is supposed to provide, and as such is an unacceptable solution.

In the thread you linked, there's a point in @alexcrichton's comment here (rustwasm/wasm-bindgen#999 (comment)) which strikes me as strange (emphasis mine):

I think you're right that taking advantage of future wasm feature "in their fullest" is likely a breaking change, but what I was hoping for is that it's a largely cosmetic breaking change rather than "rewrite the world" breaking change. For example switching some types around is pretty easy, but losing a fundamental capability (like "O(1) conversion to an integer from JsValue") runs the risk of making it much harder to migrate in the future.

Wouldn't changing an unsafe JsValue::from_raw(i32) method into JsValue::from_raw(anyref) just be a cosmetic breaking change? You aren't losing the ability to convert arbitrary integers into JsValue, because such an API would never provide that guarantee to begin with. Unsafe code can require additional semantics for proper use, and as long as a from_raw(i32) method requires handling the raw i32 similarly to how you'd handle an anyref variable you shouldn't run into any major compatibility issues when you switch the types over.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, let's think about this. The whole point of this is to expose window handle stuff as primitive types that are NOT bound to a particular version of a library. And the problem is that JsValue's are not primitive types, quite, or rather wasm-bindgen doesn't want to be able to treat them as such because the fact that they're an i32 under the hood is an implementation detail that quite realistically may change. So, if we DID expose wasm-bindgen's JsValue as integers... it would be subject to breaking changes anyway.

So, we can't expose the raw types under JsValue because it wouldn't be stable, any more than we can expose the layout of whatever structure a HWND actually points at. One solution is that 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 rather suck.

I brought this up for discussion again here: rustwasm/wasm-bindgen#1766

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on the Rust Community discord, if we're willing to limit ourselves to canvases that exist within the DOM, we can provide some sort of UUID that windowing libraries attach to canvas elements. Then, clients can find the canvas via the UUID.

Upsides:

  • We're not tied to stdweb or web-sys under the hood

Downsides:

  • Requires a bit more work on behalf of the windowing libraries (probably not too bad)
  • Does not account for canvases not inserted into the DOM (probably not important, because this library is for interop from windowing libraries)

Would this work for everyone?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be okay with that.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kinda a hack IMO, but it's a hack that should work and make it possible to use right now without needing to wait for someone else to figure their stuff out. Which is partially the point of this library.

@ryanisaacg
Copy link
Contributor Author

Ok, I've pushed up a change with a new design that doesn't tie us into the API of web-sys or stdweb.

src/web.rs Outdated
pub struct WebHandle {
/// An ID value inserted into the data attributes of the canvas element
///
/// Each canvas created by the windowing system shoudl be assigned their own unique ID.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*should

src/web.rs Outdated
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WebHandle {
/// An ID value inserted into the data attributes of the canvas element
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't specify the name of the canvas attribute.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, fixed

@Osspial Osspial merged commit 3bb8d19 into rust-windowing:master Sep 26, 2019
Copy link
Contributor

@grovesNL grovesNL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks good to me after the fact 👍

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

Successfully merging this pull request may close these issues.

4 participants