Skip to content

WebIDL Enum Support #433

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

Merged
merged 6 commits into from
Jul 11, 2018
Merged

Conversation

Slowki
Copy link
Contributor

@Slowki Slowki commented Jul 10, 2018

Adds basic support for enums to the WebIDL interface generator.

Per the consensus on #260 the enums are represented as normal Rust enums. Right now I'm just having it panic when an invalid string is converted, I was thinking of adding something along the lines of this nice hack instead, but I wanted some feedback first to see if there's a better approach.

@Slowki Slowki force-pushed the feat/basic-enum-support branch from 28adf58 to 5afca02 Compare July 10, 2018 02:37
@ohanar ohanar self-requested a review July 10, 2018 04:31
@ohanar
Copy link
Member

ohanar commented Jul 10, 2018

I haven't had the time to look through your code thoroughly (will make sure to get a chance tomorrow), but upon a first pass through everything seems fine.

I think the hack you suggested sounds like a good approach, nothing better comes to mind immediately (when I commented on the issue, I think I was thinking of doing the same thing).


fn into_abi(self, extra: &mut ::wasm_bindgen::convert::Stack) -> Self::Abi {
match self {
#(#variant_paths_ref => ::wasm_bindgen::JsValue::from_str(#variant_strings).into_abi(extra),)*
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this use the From impl below to convert this to a JsValue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

@alexcrichton
Copy link
Contributor

Nice! Just one small comment but otherwise this looks great to me

Copy link
Member

@fitzgen fitzgen 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 pull request @Slowki :)

fn from(obj: ::wasm_bindgen::JsValue) -> #name {
let obj_str = match obj.as_string() {
Some(string_value) => string_value,
None => panic!("Can't convert a non-string into {}", #name_string),
Copy link
Member

Choose a reason for hiding this comment

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

I agree that when we receive a non-string value or non-enum string value as an argument to a function that expects this enum, we should panic.

However, I don't think we should implement From<JsValue> for these and have it panic. This is too much of a footgun for folks who are just reading docs and see the impl and don't know what it does under the hood.

Instead, I think we should make a normal, non-trait pub fn from_js_value(JsValue) -> Option<Self> method, and the FromWasmAbi trait impl can unwrap the result. This gives us the same behavior when sending them to and from the ABI, but without the footgun.

Copy link
Contributor Author

@Slowki Slowki Jul 11, 2018

Choose a reason for hiding this comment

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

I think panicking in FromWasmAbi is something we should avoid so that we can recover in cases where JS functions return invalid string values.

Example

foo.webidl

enum Foo { "bar", "baz" }
Foo getFoo();

foo.js

getFoo() {
    return "quux"
}

somefile.rs

// Panics
match getFoo() {
    Foo::Bar => ...,
    Foo::Baz => ...,
}

Possible Solutions

enum Foo {
    Bar,
    Baz,
    #[doc(hidden)]
    __Invalid,
}
  • We could just expose a catch-all variant
enum Foo {
    Bar,
    Baz,
    InvalidValue(String),
}
  • Or we could make WebIDL functions which return enums return Options.

Copy link
Member

Choose a reason for hiding this comment

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

+1. I definitely wouldn't want my web app to panic if a browser gets updated with an updated version of a standard, and I haven't gotten around to upgrading my copy of web-sys.

The main downside to including the invalid value in the actual enum is that the enum no longer can be copy. I would be inclined to either just include an __Invalid variant, or have WebIDL functions returning enums to instead return Results, with an error type that contains the invalid string.

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 like the Result solution the best, it seems like it's the most convenient for the end user. The only downside is that functions that throw will end up returning Result<Result<Enum, String>, ...>, but there might be a nice way to flatten that out.

Copy link
Member

Choose a reason for hiding this comment

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

Another advantage of having non exhaustive enums is that we won't have to do breaking version bumps when updating WebIDLs.

Copy link
Member

Choose a reason for hiding this comment

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

I am working on adding support for partial and mixin interfaces right now. As part of those changes, I am doing a two pass process that would make it trivial to implement the Result return type solution. (This is in part to fix a bug in the current crate where interface objects are being passed by value, rather than by reference, as per the spec.)

I should have time today to finish up a first draft, and submit a PR. It is based off of this branch, so I would return to the non-exhaustive enum problem in a follow-up PR (especially if you want to go down the Result path).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ohanar Sounds good. I'll make from_js_value visible and resolve the merge conflict, then I'm good with this being merged.

@fitzgen That's a good point, definitely a huge + for non-exhaustive over Results.

Slowki added 3 commits July 10, 2018 20:28
Add enum support to the WebIDL interface generator.
* Remove From<JSValue> for ENUM
* Add `from_js_value` method which returns an Option<ENUM>
@Slowki Slowki force-pushed the feat/basic-enum-support branch from 5afca02 to 6608828 Compare July 11, 2018 00:29
Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

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

Thanks!

Copy link
Member

@ohanar ohanar left a comment

Choose a reason for hiding this comment

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

I am happy with merging this now, and revisiting the issue of how to handle non-exhaustive enums in the future.

}

impl #name {
fn from_js_value(obj: ::wasm_bindgen::JsValue) -> Option<#name> {
Copy link
Contributor

Choose a reason for hiding this comment

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

This may want to use #vis out in front to allow this to be used outside the module perhaps?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

Slowki added 2 commits July 11, 2018 15:34
Make from_js_value match the visibility of the enum it's associated with
@Slowki
Copy link
Contributor Author

Slowki commented Jul 11, 2018

Feel free to merge, I'll make a separate PR for the non-exhaustive enums issue.

Update the enum test to match the new constructor return values
@fitzgen
Copy link
Member

fitzgen commented Jul 11, 2018

Feel free to merge, I'll make a separate PR for the non-exhaustive enums issue.

SGTM! Thanks @Slowki :)

@fitzgen fitzgen merged commit 9c7b15e into rustwasm:master Jul 11, 2018
@Slowki Slowki deleted the feat/basic-enum-support branch July 11, 2018 22:31
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

Successfully merging this pull request may close these issues.

4 participants