diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 0507f055306..0807f3b9463 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -475,8 +475,10 @@ pub struct Enum { #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[derive(Clone)] pub struct Variant { - /// The name of this variant - pub name: Ident, + /// The name of this variant in Rust + pub rust_name: Ident, + /// The name of this variant in JS + pub js_name: String, /// The backing value of this variant pub value: u32, /// The doc comments on this variant, if any diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 23599fc87b0..6f41bbe8e8b 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -1543,7 +1543,7 @@ impl ToTokens for ast::Enum { quote! { u32 } }; let cast_clauses = self.variants.iter().map(|variant| { - let variant_name = &variant.name; + let variant_name = &variant.rust_name; quote! { if js == #enum_name::#variant_name as #underlying { #enum_name::#variant_name diff --git a/crates/backend/src/encode.rs b/crates/backend/src/encode.rs index d98fe628450..f05e9ad7057 100644 --- a/crates/backend/src/encode.rs +++ b/crates/backend/src/encode.rs @@ -150,7 +150,7 @@ fn shared_program<'a>( .iter() .map(|a| shared_struct(a, intern)) .collect(), - enums: prog.enums.iter().map(|a| shared_enum(a, intern)).collect(), + enums: prog.enums.iter().map(|a| shared_enum(a)).collect(), imports: prog .imports .iter() @@ -236,23 +236,19 @@ fn shared_function<'a>(func: &'a ast::Function, _intern: &'a Interner) -> Functi } } -fn shared_enum<'a>(e: &'a ast::Enum, intern: &'a Interner) -> Enum<'a> { +fn shared_enum(e: &ast::Enum) -> Enum { Enum { name: &e.js_name, signed: e.signed, - variants: e - .variants - .iter() - .map(|v| shared_variant(v, intern)) - .collect(), + variants: e.variants.iter().map(shared_variant).collect(), comments: e.comments.iter().map(|s| &**s).collect(), generate_typescript: e.generate_typescript, } } -fn shared_variant<'a>(v: &'a ast::Variant, intern: &'a Interner) -> EnumVariant<'a> { +fn shared_variant(v: &ast::Variant) -> EnumVariant { EnumVariant { - name: intern.intern(&v.name), + name: v.js_name.as_str(), value: v.value, comments: v.comments.iter().map(|s| &**s).collect(), } diff --git a/crates/cli/tests/reference/raw.d.ts b/crates/cli/tests/reference/raw.d.ts index b28681c178f..67f937afcc4 100644 --- a/crates/cli/tests/reference/raw.d.ts +++ b/crates/cli/tests/reference/raw.d.ts @@ -1,6 +1,9 @@ /* tslint:disable */ /* eslint-disable */ export function test1(test: number): number; +export enum Enum { + A = 0, +} export class Test { private constructor(); free(): void; diff --git a/crates/cli/tests/reference/raw.js b/crates/cli/tests/reference/raw.js index 4e9035bbf26..ed161b054fe 100644 --- a/crates/cli/tests/reference/raw.js +++ b/crates/cli/tests/reference/raw.js @@ -32,6 +32,13 @@ export function test1(test) { return ret >>> 0; } +/** + * @enum {0} + */ +export const Enum = Object.freeze({ + A: 0, "0": "A", +}); + const TestFinalization = (typeof FinalizationRegistry === 'undefined') ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry(ptr => wasm.__wbg_test_free(ptr >>> 0, 1)); diff --git a/crates/cli/tests/reference/raw.rs b/crates/cli/tests/reference/raw.rs index 7c49eba5b04..9a48d18fef8 100644 --- a/crates/cli/tests/reference/raw.rs +++ b/crates/cli/tests/reference/raw.rs @@ -22,3 +22,8 @@ impl r#Test { extern "C" { fn r#test2() -> JsValue; } + +#[wasm_bindgen] +pub enum r#Enum { + r#A, +} diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 9d7ad85a00c..05afcab4ee0 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -254,6 +254,20 @@ impl BindgenAttrs { Ok(thread_local) } + /// Returns the JS name from the given attributes, or the Rust name if not present. + fn js_name_or_ident(&self, ident: &Ident) -> String { + self.js_name() + .map(|(n, _)| n.to_string()) + .unwrap_or_else(|| ident.unraw().to_string()) + } + + /// Returns the JS class from the given attributes, or the Rust name if not present. + fn js_class_or_ident(&self, ident: &Ident) -> String { + self.js_class() + .map(|(n, _)| n.to_string()) + .unwrap_or_else(|| ident.unraw().to_string()) + } + attrgen!(methods); } @@ -437,10 +451,7 @@ impl ConvertToAst<(&ast::Program, BindgenAttrs)> for &mut syn::ItemStruct { ); } let mut fields = Vec::new(); - let js_name = attrs - .js_name() - .map(|s| s.0.to_string()) - .unwrap_or(self.ident.unraw().to_string()); + let js_name = attrs.js_name_or_ident(&self.ident); let is_inspectable = attrs.inspectable().is_some(); let getter_with_clone = attrs.getter_with_clone(); for (i, field) in self.fields.iter_mut().enumerate() { @@ -573,11 +584,7 @@ impl<'a> ConvertToAst<(&ast::Program, BindgenAttrs, &'a Option path, _ => bail_span!(class, "first argument of method must be a path"), }; - let class_name = extract_path_ident(class_name)?; - let class_name = opts - .js_class() - .map(|p| p.0.into()) - .unwrap_or_else(|| class_name.to_string()); + let class_name = opts.js_class_or_ident(&extract_path_ident(class_name)?); let kind = ast::MethodKind::Operation(ast::Operation { is_static: false, @@ -590,10 +597,7 @@ impl<'a> ConvertToAst<(&ast::Program, BindgenAttrs, &'a Option ConvertToAst<(&ast::Program, BindgenAttrs, &'a Option path, _ => bail_span!(self, "return value of constructor must be a bare path"), }; - let class_name = extract_path_ident(class_name)?; - let class_name = opts - .js_class() - .map(|p| p.0.into()) - .unwrap_or_else(|| class_name.to_string()); + let class_name = opts.js_class_or_ident(&extract_path_ident(class_name)?); ast::ImportFunctionKind::Method { class: class_name, @@ -718,10 +718,7 @@ impl ConvertToAst<(&ast::Program, BindgenAttrs)> for syn::ForeignItemType { self, (program, attrs): (&ast::Program, BindgenAttrs), ) -> Result { - let js_name = attrs - .js_name() - .map(|s| s.0) - .map_or_else(|| self.ident.to_string(), |s| s.to_string()); + let js_name = attrs.js_name_or_ident(&self.ident); let typescript_type = attrs.typescript_type().map(|s| s.0.to_string()); let is_type_of = attrs.is_type_of().cloned(); let shim = format!( @@ -783,12 +780,7 @@ impl<'a> ConvertToAst<(&ast::Program, BindgenAttrs, &'a Option bail_span!(other, "failed to parse this item as a known item"), }; - let ident = extract_path_ident(class)?; - - let js_class = impl_opts - .js_class() - .map(|s| s.0.to_string()) - .unwrap_or(ident.to_string()); + let js_class = impl_opts.js_class_or_ident(&extract_path_ident(class)?); let wasm_bindgen = &program.wasm_bindgen; let wasm_bindgen_futures = &program.wasm_bindgen_futures; @@ -1481,10 +1468,7 @@ impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum { } let generate_typescript = opts.skip_typescript().is_none(); - let js_name = opts - .js_name() - .map(|s| s.0) - .map_or_else(|| self.ident.to_string(), |s| s.to_string()); + let js_name = opts.js_name_or_ident(&self.ident); let comments = extract_doc_comments(&self.attrs); opts.check_used(); @@ -1588,7 +1572,8 @@ impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum { let comments = extract_doc_comments(&v.attrs); Ok(ast::Variant { - name: v.ident.clone(), + rust_name: v.ident.clone(), + js_name: v.ident.unraw().to_string(), // due to the above checks, we know that the value fits // within 32 bits, so this cast doesn't lose any information value: value as u32,