mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 18:20:51 +00:00
WebIDL: Handle Invalid Enum Returns (#477)
* move ImportEnum attributes to a property * borrow from_js_value argument * make WebIDL enums non-exhaustive * add more tests for WebIDL enums
This commit is contained in:
parent
5fddcf3868
commit
b3ee71c20b
@ -112,6 +112,8 @@ pub struct ImportEnum {
|
||||
pub variants: Vec<Ident>,
|
||||
/// The JS string values of the variants
|
||||
pub variant_values: Vec<String>,
|
||||
/// Attributes to apply to the Rust enum
|
||||
pub rust_attrs: Vec<syn::Attribute>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
|
@ -580,9 +580,10 @@ impl ToTokens for ast::ImportEnum {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let vis = &self.vis;
|
||||
let name = &self.name;
|
||||
let expect_string = format!("attempted to convert invalid JSValue into {}", name);
|
||||
let expect_string = format!("attempted to convert invalid {} into JSValue", name);
|
||||
let variants = &self.variants;
|
||||
let variant_strings = &self.variant_values;
|
||||
let attrs = &self.rust_attrs;
|
||||
|
||||
let mut current_idx: usize = 0;
|
||||
let variant_indexes: Vec<Literal> = variants
|
||||
@ -609,13 +610,15 @@ impl ToTokens for ast::ImportEnum {
|
||||
|
||||
(quote! {
|
||||
#[allow(bad_style)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#(#attrs)*
|
||||
#vis enum #name {
|
||||
#(#variants = #variant_indexes_ref,)*
|
||||
#[doc(hidden)]
|
||||
__Nonexhaustive,
|
||||
}
|
||||
|
||||
impl #name {
|
||||
#vis fn from_js_value(obj: ::wasm_bindgen::JsValue) -> Option<#name> {
|
||||
#vis fn from_js_value(obj: &::wasm_bindgen::JsValue) -> Option<#name> {
|
||||
obj.as_string().and_then(|obj_str| match obj_str.as_str() {
|
||||
#(#variant_strings => Some(#variant_paths_ref),)*
|
||||
_ => None,
|
||||
@ -646,14 +649,15 @@ impl ToTokens for ast::ImportEnum {
|
||||
js: Self::Abi,
|
||||
extra: &mut ::wasm_bindgen::convert::Stack,
|
||||
) -> Self {
|
||||
#name::from_js_value(::wasm_bindgen::JsValue::from_abi(js, extra)).expect(#expect_string)
|
||||
#name::from_js_value(&::wasm_bindgen::JsValue::from_abi(js, extra)).unwrap_or(#name::__Nonexhaustive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<#name> for ::wasm_bindgen::JsValue {
|
||||
fn from(obj: #name) -> ::wasm_bindgen::JsValue {
|
||||
match obj {
|
||||
#(#variant_paths_ref => ::wasm_bindgen::JsValue::from_str(#variant_strings)),*
|
||||
#(#variant_paths_ref => ::wasm_bindgen::JsValue::from_str(#variant_strings),)*
|
||||
#name::__Nonexhaustive => panic!(#expect_string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,9 @@ extern crate heck;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate proc_macro2;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
extern crate wasm_bindgen_backend as backend;
|
||||
extern crate webidl;
|
||||
@ -640,6 +642,7 @@ impl<'a> WebidlParse<()> for webidl::ast::Enum {
|
||||
.map(|v| rust_ident(v.to_camel_case().as_str()))
|
||||
.collect(),
|
||||
variant_values: self.variants.clone(),
|
||||
rust_attrs: vec![parse_quote!(#[derive(Copy, Clone, PartialEq, Debug)])],
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -1,23 +1,25 @@
|
||||
use super::project;
|
||||
|
||||
static SHAPE_IDL: &'static str = r#"
|
||||
enum ShapeType { "circle", "square" };
|
||||
|
||||
[Constructor(ShapeType kind)]
|
||||
interface Shape {
|
||||
[Pure]
|
||||
boolean isSquare();
|
||||
|
||||
[Pure]
|
||||
boolean isCircle();
|
||||
|
||||
[Pure]
|
||||
ShapeType getShape();
|
||||
};
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn top_level_enum() {
|
||||
project()
|
||||
.file(
|
||||
"shape.webidl",
|
||||
r#"
|
||||
enum ShapeType { "circle", "square" };
|
||||
|
||||
[Constructor(ShapeType kind)]
|
||||
interface Shape {
|
||||
[Pure]
|
||||
boolean isSquare();
|
||||
|
||||
[Pure]
|
||||
boolean isCircle();
|
||||
};
|
||||
"#,
|
||||
)
|
||||
.file("shape.webidl", SHAPE_IDL)
|
||||
.file(
|
||||
"shape.mjs",
|
||||
r#"
|
||||
@ -33,6 +35,10 @@ fn top_level_enum() {
|
||||
isCircle() {
|
||||
return this.kind === 'circle';
|
||||
}
|
||||
|
||||
getShape() {
|
||||
return this.kind;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
@ -62,3 +68,112 @@ fn top_level_enum() {
|
||||
)
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_enum_return() {
|
||||
project()
|
||||
.file("shape.webidl", SHAPE_IDL)
|
||||
.file(
|
||||
"shape.mjs",
|
||||
r#"
|
||||
export class Shape {
|
||||
constructor(kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
isSquare() {
|
||||
return this.kind === 'square';
|
||||
}
|
||||
|
||||
isCircle() {
|
||||
return this.kind === 'circle';
|
||||
}
|
||||
|
||||
getShape() {
|
||||
return this.kind;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"src/lib.rs",
|
||||
r#"
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod shape;
|
||||
|
||||
use shape::{Shape, ShapeType};
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn test() {
|
||||
let circle = Shape::new(ShapeType::Circle).unwrap();
|
||||
let square = Shape::new(ShapeType::Square).unwrap();
|
||||
assert!(circle.is_circle());
|
||||
assert!(!circle.is_square());
|
||||
assert_eq!(circle.get_shape(), ShapeType::Circle);
|
||||
assert!(square.is_square());
|
||||
assert!(!square.is_circle());
|
||||
assert_eq!(square.get_shape(), ShapeType::Square);
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_enum_return() {
|
||||
project()
|
||||
.file("shape.webidl", SHAPE_IDL)
|
||||
.file(
|
||||
"shape.mjs",
|
||||
r#"
|
||||
export class Shape {
|
||||
constructor(kind) {
|
||||
this.kind = 'triangle'; // <-- invalid ShapeType
|
||||
}
|
||||
|
||||
isSquare() {
|
||||
return this.kind === 'square';
|
||||
}
|
||||
|
||||
isCircle() {
|
||||
return this.kind === 'circle';
|
||||
}
|
||||
|
||||
getShape() {
|
||||
return this.kind;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"src/lib.rs",
|
||||
r#"
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod shape;
|
||||
|
||||
use shape::{Shape, ShapeType};
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn test() {
|
||||
let actually_a_triangle = Shape::new(ShapeType::Circle).unwrap();
|
||||
assert!(!actually_a_triangle.is_circle());
|
||||
assert!(!actually_a_triangle.is_square());
|
||||
match actually_a_triangle.get_shape() {
|
||||
ShapeType::Circle | ShapeType::Square => assert!(false),
|
||||
_ => {} // Success
|
||||
};
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.test();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user