mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2024-11-25 09:02:46 +03:00
Merge pull request #433 from Slowki/feat/basic-enum-support
WebIDL Enum Support
This commit is contained in:
commit
9c7b15ea40
@ -41,6 +41,7 @@ pub enum ImportKind {
|
|||||||
Function(ImportFunction),
|
Function(ImportFunction),
|
||||||
Static(ImportStatic),
|
Static(ImportStatic),
|
||||||
Type(ImportType),
|
Type(ImportType),
|
||||||
|
Enum(ImportEnum),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
@ -99,6 +100,18 @@ pub struct ImportType {
|
|||||||
pub attrs: Vec<syn::Attribute>,
|
pub attrs: Vec<syn::Attribute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
|
pub struct ImportEnum {
|
||||||
|
/// The Rust enum's visibility
|
||||||
|
pub vis: syn::Visibility,
|
||||||
|
/// The Rust enum's identifiers
|
||||||
|
pub name: Ident,
|
||||||
|
/// The Rust identifiers for the variants
|
||||||
|
pub variants: Vec<Ident>,
|
||||||
|
/// The JS string values of the variants
|
||||||
|
pub variant_values: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
@ -279,6 +292,7 @@ impl ImportKind {
|
|||||||
ImportKind::Function(_) => true,
|
ImportKind::Function(_) => true,
|
||||||
ImportKind::Static(_) => false,
|
ImportKind::Static(_) => false,
|
||||||
ImportKind::Type(_) => false,
|
ImportKind::Type(_) => false,
|
||||||
|
ImportKind::Enum(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +301,7 @@ impl ImportKind {
|
|||||||
ImportKind::Function(ref f) => shared::ImportKind::Function(f.shared()),
|
ImportKind::Function(ref f) => shared::ImportKind::Function(f.shared()),
|
||||||
ImportKind::Static(ref f) => shared::ImportKind::Static(f.shared()),
|
ImportKind::Static(ref f) => shared::ImportKind::Static(f.shared()),
|
||||||
ImportKind::Type(ref f) => shared::ImportKind::Type(f.shared()),
|
ImportKind::Type(ref f) => shared::ImportKind::Type(f.shared()),
|
||||||
|
ImportKind::Enum(ref f) => shared::ImportKind::Enum(f.shared()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,6 +379,12 @@ impl ImportType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImportEnum {
|
||||||
|
fn shared(&self) -> shared::ImportEnum {
|
||||||
|
shared::ImportEnum {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Struct {
|
impl Struct {
|
||||||
fn shared(&self) -> shared::Struct {
|
fn shared(&self) -> shared::Struct {
|
||||||
shared::Struct {
|
shared::Struct {
|
||||||
|
@ -4,7 +4,7 @@ use std::env;
|
|||||||
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||||
|
|
||||||
use ast;
|
use ast;
|
||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use shared;
|
use shared;
|
||||||
@ -500,6 +500,7 @@ impl ToTokens for ast::ImportKind {
|
|||||||
ast::ImportKind::Function(ref f) => f.to_tokens(tokens),
|
ast::ImportKind::Function(ref f) => f.to_tokens(tokens),
|
||||||
ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
|
ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
|
||||||
ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
|
ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
|
||||||
|
ast::ImportKind::Enum(ref e) => e.to_tokens(tokens),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -586,6 +587,91 @@ impl ToTokens for ast::ImportType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 variants = &self.variants;
|
||||||
|
let variant_strings = &self.variant_values;
|
||||||
|
|
||||||
|
let mut current_idx: usize = 0;
|
||||||
|
let variant_indexes: Vec<Literal> = variants
|
||||||
|
.iter()
|
||||||
|
.map(|_| {
|
||||||
|
let this_index = current_idx;
|
||||||
|
current_idx += 1;
|
||||||
|
Literal::usize_unsuffixed(this_index)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Borrow variant_indexes because we need to use it multiple times inside the quote! macro
|
||||||
|
let variant_indexes_ref = &variant_indexes;
|
||||||
|
|
||||||
|
// A vector of EnumName::VariantName tokens for this enum
|
||||||
|
let variant_paths: Vec<TokenStream> = self
|
||||||
|
.variants
|
||||||
|
.iter()
|
||||||
|
.map(|v| quote!(#name::#v).into_token_stream())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Borrow variant_paths because we need to use it multiple times inside the quote! macro
|
||||||
|
let variant_paths_ref = &variant_paths;
|
||||||
|
|
||||||
|
(quote! {
|
||||||
|
#[allow(bad_style)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#vis enum #name {
|
||||||
|
#(#variants = #variant_indexes_ref,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::describe::WasmDescribe for #name {
|
||||||
|
fn describe() {
|
||||||
|
::wasm_bindgen::JsValue::describe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::convert::IntoWasmAbi for #name {
|
||||||
|
type Abi = <::wasm_bindgen::JsValue as
|
||||||
|
::wasm_bindgen::convert::IntoWasmAbi>::Abi;
|
||||||
|
|
||||||
|
fn into_abi(self, extra: &mut ::wasm_bindgen::convert::Stack) -> Self::Abi {
|
||||||
|
::wasm_bindgen::JsValue::from(self).into_abi(extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::convert::FromWasmAbi for #name {
|
||||||
|
type Abi = <::wasm_bindgen::JsValue as
|
||||||
|
::wasm_bindgen::convert::FromWasmAbi>::Abi;
|
||||||
|
|
||||||
|
unsafe fn from_abi(
|
||||||
|
js: Self::Abi,
|
||||||
|
extra: &mut ::wasm_bindgen::convert::Stack,
|
||||||
|
) -> Self {
|
||||||
|
#name::from_js_value(::wasm_bindgen::JsValue::from_abi(js, extra)).expect(#expect_string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToTokens for ast::ImportFunction {
|
impl ToTokens for ast::ImportFunction {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let mut class_ty = None;
|
let mut class_ty = None;
|
||||||
@ -755,6 +841,7 @@ impl<'a> ToTokens for DescribeImport<'a> {
|
|||||||
ast::ImportKind::Function(ref f) => f,
|
ast::ImportKind::Function(ref f) => f,
|
||||||
ast::ImportKind::Static(_) => return,
|
ast::ImportKind::Static(_) => return,
|
||||||
ast::ImportKind::Type(_) => return,
|
ast::ImportKind::Type(_) => return,
|
||||||
|
ast::ImportKind::Enum(_) => return,
|
||||||
};
|
};
|
||||||
let describe_name = format!("__wbindgen_describe_{}", f.shim);
|
let describe_name = format!("__wbindgen_describe_{}", f.shim);
|
||||||
let describe_name = Ident::new(&describe_name, Span::call_site());
|
let describe_name = Ident::new(&describe_name, Span::call_site());
|
||||||
|
@ -105,6 +105,7 @@ impl ImportedTypes for ast::ImportKind {
|
|||||||
ast::ImportKind::Static(s) => s.imported_types(f),
|
ast::ImportKind::Static(s) => s.imported_types(f),
|
||||||
ast::ImportKind::Function(fun) => fun.imported_types(f),
|
ast::ImportKind::Function(fun) => fun.imported_types(f),
|
||||||
ast::ImportKind::Type(ty) => ty.imported_types(f),
|
ast::ImportKind::Type(ty) => ty.imported_types(f),
|
||||||
|
ast::ImportKind::Enum(enm) => enm.imported_types(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,6 +211,15 @@ impl ImportedTypes for ast::ImportType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImportedTypes for ast::ImportEnum {
|
||||||
|
fn imported_types<F>(&self, f: &mut F)
|
||||||
|
where
|
||||||
|
F: FnMut(&Ident, ImportedTypeKind),
|
||||||
|
{
|
||||||
|
f(&self.name, ImportedTypeKind::Definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ImportedTypes for ast::TypeAlias {
|
impl ImportedTypes for ast::TypeAlias {
|
||||||
fn imported_types<F>(&self, f: &mut F)
|
fn imported_types<F>(&self, f: &mut F)
|
||||||
where
|
where
|
||||||
|
@ -71,13 +71,15 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self.prelude(
|
self.prelude(
|
||||||
"if (this.ptr === 0) {
|
"if (this.ptr === 0) {
|
||||||
throw new Error('Attempt to use a moved value');
|
throw new Error('Attempt to use a moved value');
|
||||||
}"
|
}",
|
||||||
);
|
);
|
||||||
if consumed {
|
if consumed {
|
||||||
self.prelude("\
|
self.prelude(
|
||||||
const ptr = this.ptr;\n\
|
"\
|
||||||
this.ptr = 0;\n\
|
const ptr = this.ptr;\n\
|
||||||
");
|
this.ptr = 0;\n\
|
||||||
|
",
|
||||||
|
);
|
||||||
self.rust_arguments.insert(0, "ptr".to_string());
|
self.rust_arguments.insert(0, "ptr".to_string());
|
||||||
} else {
|
} else {
|
||||||
self.rust_arguments.insert(0, "this.ptr".to_string());
|
self.rust_arguments.insert(0, "this.ptr".to_string());
|
||||||
|
@ -1756,6 +1756,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
shared::ImportKind::Type(_) => {}
|
shared::ImportKind::Type(_) => {}
|
||||||
|
shared::ImportKind::Enum(_) => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,8 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
// Insert an assertion to the type of the returned value as
|
// Insert an assertion to the type of the returned value as
|
||||||
// otherwise this will cause memory unsafety on the Rust side of
|
// otherwise this will cause memory unsafety on the Rust side of
|
||||||
// things.
|
// things.
|
||||||
self.ret_expr = format!("\
|
self.ret_expr = format!(
|
||||||
|
"\
|
||||||
const val = JS;
|
const val = JS;
|
||||||
if (!(val instanceof {0})) {{
|
if (!(val instanceof {0})) {{
|
||||||
throw new Error('expected value of type {0}');
|
throw new Error('expected value of type {0}');
|
||||||
@ -314,8 +315,10 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
const ret = val.ptr;
|
const ret = val.ptr;
|
||||||
val.ptr = 0;
|
val.ptr = 0;
|
||||||
return ret;\
|
return ret;\
|
||||||
", class);
|
",
|
||||||
return Ok(())
|
class
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ret_expr = match *ty {
|
self.ret_expr = match *ty {
|
||||||
|
@ -33,6 +33,7 @@ pub enum ImportKind {
|
|||||||
Function(ImportFunction),
|
Function(ImportFunction),
|
||||||
Static(ImportStatic),
|
Static(ImportStatic),
|
||||||
Type(ImportType),
|
Type(ImportType),
|
||||||
|
Enum(ImportEnum),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
@ -78,6 +79,9 @@ pub struct ImportStatic {
|
|||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct ImportType {}
|
pub struct ImportType {}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct ImportEnum {}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct Export {
|
pub struct Export {
|
||||||
pub class: Option<String>,
|
pub class: Option<String>,
|
||||||
|
@ -29,6 +29,7 @@ use std::path::Path;
|
|||||||
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
|
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
|
||||||
use backend::util::{ident_ty, rust_ident, wrap_import_function};
|
use backend::util::{ident_ty, rust_ident, wrap_import_function};
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
|
use heck::CamelCase;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
|
||||||
use util::{
|
use util::{
|
||||||
@ -111,10 +112,10 @@ impl WebidlParse<()> for webidl::ast::Definition {
|
|||||||
interface.webidl_parse(program, ())
|
interface.webidl_parse(program, ())
|
||||||
}
|
}
|
||||||
webidl::ast::Definition::Typedef(ref typedef) => typedef.webidl_parse(program, ()),
|
webidl::ast::Definition::Typedef(ref typedef) => typedef.webidl_parse(program, ()),
|
||||||
|
webidl::ast::Definition::Enum(ref enumeration) => enumeration.webidl_parse(program, ()),
|
||||||
// TODO
|
// TODO
|
||||||
webidl::ast::Definition::Callback(..)
|
webidl::ast::Definition::Callback(..)
|
||||||
| webidl::ast::Definition::Dictionary(..)
|
| webidl::ast::Definition::Dictionary(..)
|
||||||
| webidl::ast::Definition::Enum(..)
|
|
||||||
| webidl::ast::Definition::Implements(..)
|
| webidl::ast::Definition::Implements(..)
|
||||||
| webidl::ast::Definition::Includes(..)
|
| webidl::ast::Definition::Includes(..)
|
||||||
| webidl::ast::Definition::Mixin(..)
|
| webidl::ast::Definition::Mixin(..)
|
||||||
@ -449,3 +450,27 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> WebidlParse<()> for webidl::ast::Enum {
|
||||||
|
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
||||||
|
program.imports.push(backend::ast::Import {
|
||||||
|
module: None,
|
||||||
|
version: None,
|
||||||
|
js_namespace: None,
|
||||||
|
kind: backend::ast::ImportKind::Enum(backend::ast::ImportEnum {
|
||||||
|
vis: syn::Visibility::Public(syn::VisPublic {
|
||||||
|
pub_token: Default::default(),
|
||||||
|
}),
|
||||||
|
name: rust_ident(self.name.to_camel_case().as_str()),
|
||||||
|
variants: self
|
||||||
|
.variants
|
||||||
|
.iter()
|
||||||
|
.map(|v| rust_ident(v.to_camel_case().as_str()))
|
||||||
|
.collect(),
|
||||||
|
variant_values: self.variants.clone(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
64
crates/webidl/tests/all/enums.rs
Normal file
64
crates/webidl/tests/all/enums.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use super::project;
|
||||||
|
|
||||||
|
#[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.mjs",
|
||||||
|
r#"
|
||||||
|
export class Shape {
|
||||||
|
constructor(kind) {
|
||||||
|
this.kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSquare() {
|
||||||
|
return this.kind === 'square';
|
||||||
|
}
|
||||||
|
|
||||||
|
isCircle() {
|
||||||
|
return this.kind === 'circle';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"src/lib.rs",
|
||||||
|
r#"
|
||||||
|
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||||
|
|
||||||
|
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!(square.is_square());
|
||||||
|
assert!(!square.is_circle());
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.test();
|
||||||
|
}
|
@ -2,4 +2,5 @@ extern crate wasm_bindgen_test_project_builder as project_builder;
|
|||||||
use project_builder::project;
|
use project_builder::project;
|
||||||
|
|
||||||
mod simple;
|
mod simple;
|
||||||
|
mod enums;
|
||||||
mod throws;
|
mod throws;
|
||||||
|
Loading…
Reference in New Issue
Block a user