-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
WebIDL Enum Support #433
Conversation
28adf58
to
5afca02
Compare
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). |
crates/backend/src/codegen.rs
Outdated
|
||
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),)* |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Nice! Just one small comment but otherwise this looks great to me |
There was a problem hiding this 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 :)
crates/backend/src/codegen.rs
Outdated
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), |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
- We could use this idiom from libstd and return
__Invalid
instead of panicking
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
Option
s.
There was a problem hiding this comment.
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 Result
s, with an error type that contains the invalid string.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 enum
s is that we won't have to do breaking version bumps when updating WebIDLs.
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add enum support to the WebIDL interface generator.
* Remove From<JSValue> for ENUM * Add `from_js_value` method which returns an Option<ENUM>
5afca02
to
6608828
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
There was a problem hiding this 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.
crates/backend/src/codegen.rs
Outdated
} | ||
|
||
impl #name { | ||
fn from_js_value(obj: ::wasm_bindgen::JsValue) -> Option<#name> { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Make from_js_value match the visibility of the enum it's associated with
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
SGTM! Thanks @Slowki :) |
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.