From 01c31cb33dd3eb5c4bc7ada1130491434b291c71 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 22 Feb 2018 00:55:11 +0100 Subject: [PATCH] Create Rust wrapping code for enums --- crates/wasm-bindgen-macro/src/ast.rs | 35 ++++++++++++++++++++++++++- crates/wasm-bindgen-macro/src/lib.rs | 30 +++++++++++++++++++++++ crates/wasm-bindgen-shared/src/lib.rs | 1 + 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/crates/wasm-bindgen-macro/src/ast.rs b/crates/wasm-bindgen-macro/src/ast.rs index 0920cdac..1899a6dc 100644 --- a/crates/wasm-bindgen-macro/src/ast.rs +++ b/crates/wasm-bindgen-macro/src/ast.rs @@ -9,6 +9,7 @@ use syn; pub struct Program { pub exports: Vec, pub imports: Vec, + pub enums: Vec, pub imported_types: Vec<(syn::Visibility, syn::Ident)>, pub structs: Vec, } @@ -47,6 +48,10 @@ pub struct Struct { pub name: syn::Ident, } +pub struct Enum { + pub name: syn::Ident +} + pub enum Type { // special Vector(VectorType, bool), @@ -110,8 +115,13 @@ impl Program { let opts = opts.unwrap_or_else(|| BindgenAttrs::find(&mut f.attrs)); self.push_foreign_mod(f, opts); } + syn::Item::Enum(mut e) => { + let opts = opts.unwrap_or_else(|| BindgenAttrs::find(&mut e.attrs)); + e.to_tokens(tokens); + self.push_enum(e, opts); + } _ => panic!("#[wasm_bindgen] can only be applied to a function, \ - struct, impl, or extern block"), + struct, enum, impl, or extern block"), } } @@ -195,6 +205,28 @@ impl Program { } } + pub fn push_enum(&mut self, item: syn::ItemEnum, opts: BindgenAttrs) { + match item.vis { + syn::Visibility::Public(_) => {} + _ => panic!("only public enums are allowed"), + } + + let all_fields_unit = item.variants.iter().all(|ref v| { + match v.fields { + syn::Fields::Unit => true, + _ => false + } + }); + if all_fields_unit { + self.enums.push(Enum { + name: item.ident + }); + + } else { + panic!("Only C-Style enums allowed") + } + } + pub fn push_foreign_fn(&mut self, mut f: syn::ForeignItemFn, module_opts: &BindgenAttrs) { @@ -301,6 +333,7 @@ impl Program { let names = self.exports.iter() .filter_map(|e| e.class) .chain(self.structs.iter().map(|s| s.name)) + .chain(self.enums.iter().map(|s| s.name)) .collect::>(); a.list(&names, |s, a| { let val = shared::name_to_descriptor(s.as_ref()); diff --git a/crates/wasm-bindgen-macro/src/lib.rs b/crates/wasm-bindgen-macro/src/lib.rs index 1878bb00..039d23ff 100644 --- a/crates/wasm-bindgen-macro/src/lib.rs +++ b/crates/wasm-bindgen-macro/src/lib.rs @@ -50,6 +50,9 @@ fn generate_wrappers(program: ast::Program, tokens: &mut Tokens) { for i in program.imports.iter() { bindgen_import(i, tokens); } + for e in program.enums.iter() { + bindgen_enum(e, tokens); + } for &(ref vis, ref t) in program.imported_types.iter() { bindgen_imported_type(vis, t, tokens); } @@ -510,3 +513,30 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) { invocation.to_tokens(tokens); } } + +fn bindgen_enum(e: &ast::Enum, into: &mut Tokens) { + let name = &e.name; + let c = shared::name_to_descriptor(name.as_ref()) as u32; + (my_quote! { + impl #name { + fn from_usize(n: usize) -> #name { + #name::Blue + } + } + impl ::wasm_bindgen::convert::WasmBoundary for #name { + type Js = u32; + const DESCRIPTOR: u32 = #c; + + fn into_js(self) -> u32 { + Box::into_raw(Box::new(self as u32)) as u32 + } + + unsafe fn from_js(js: u32) -> Self { + let js = js as *mut usize; + ::wasm_bindgen::__rt::assert_not_null(js); + let js = Box::from_raw(js); + #name::from_usize(*js) + } + } + }).to_tokens(into); +} diff --git a/crates/wasm-bindgen-shared/src/lib.rs b/crates/wasm-bindgen-shared/src/lib.rs index 7fe56b5d..2047ce99 100644 --- a/crates/wasm-bindgen-shared/src/lib.rs +++ b/crates/wasm-bindgen-shared/src/lib.rs @@ -77,6 +77,7 @@ pub fn mangled_import_name(struct_: Option<&str>, f: &str) -> String { pub type Type = char; +pub const TYPE_ENUM: char = '\u{5d}'; pub const TYPE_NUMBER: char = '\u{5e}'; pub const TYPE_BORROWED_STR: char = '\u{5f}'; pub const TYPE_STRING: char = '\u{60}';