From 3a7d384dc8d28d7c04bb0d04debfda7dcc490ddf Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Tue, 16 Apr 2019 20:31:25 +0100 Subject: [PATCH] Generate bindings for indexed struct properties This allows to export fields of tuple-like structs as indexed JS properties. --- crates/backend/src/ast.rs | 2 +- crates/backend/src/encode.rs | 5 ++- crates/macro-support/src/parser.rs | 63 ++++++++++++++---------------- tests/wasm/classes.js | 1 + tests/wasm/classes.rs | 11 ++++++ 5 files changed, 47 insertions(+), 35 deletions(-) diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index aeb56ccb..c54a27be 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -227,7 +227,7 @@ pub struct Struct { #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[derive(Clone)] pub struct StructField { - pub name: Ident, + pub name: syn::Member, pub struct_name: Ident, pub readonly: bool, pub ty: syn::Type, diff --git a/crates/backend/src/encode.rs b/crates/backend/src/encode.rs index b0cc9cb6..ae8d4cd3 100644 --- a/crates/backend/src/encode.rs +++ b/crates/backend/src/encode.rs @@ -332,7 +332,10 @@ fn shared_struct<'a>(s: &'a ast::Struct, intern: &'a Interner) -> Struct<'a> { fn shared_struct_field<'a>(s: &'a ast::StructField, intern: &'a Interner) -> StructField<'a> { StructField { - name: intern.intern(&s.name), + name: match &s.name { + syn::Member::Named(ident) => intern.intern(ident), + syn::Member::Unnamed(index) => intern.intern_str(&index.index.to_string()), + }, readonly: s.readonly, comments: s.comments.iter().map(|s| &**s).collect(), } diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 998b6a8f..165e76f4 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -309,40 +309,37 @@ impl<'a> ConvertToAst for &'a mut syn::ItemStruct { .js_name() .map(|s| s.0.to_string()) .unwrap_or(self.ident.to_string()); - if let syn::Fields::Named(names) = &mut self.fields { - for field in names.named.iter_mut() { - match field.vis { - syn::Visibility::Public(..) => {} - _ => continue, - } - let name = match &field.ident { - Some(n) => n, - None => continue, - }; - - let attrs = BindgenAttrs::find(&mut field.attrs)?; - assert_not_variadic(&attrs)?; - if attrs.skip().is_some() { - attrs.check_used()?; - continue; - } - - let comments = extract_doc_comments(&field.attrs); - let name_str = name.to_string(); - let getter = shared::struct_field_get(&js_name, &name_str); - let setter = shared::struct_field_set(&js_name, &name_str); - - fields.push(ast::StructField { - name: name.clone(), - struct_name: self.ident.clone(), - readonly: attrs.readonly().is_some(), - ty: field.ty.clone(), - getter: Ident::new(&getter, Span::call_site()), - setter: Ident::new(&setter, Span::call_site()), - comments, - }); - attrs.check_used()?; + for (i, field) in self.fields.iter_mut().enumerate() { + match field.vis { + syn::Visibility::Public(..) => {} + _ => continue, } + let (name_str, member) = match &field.ident { + Some(ident) => (ident.to_string(), syn::Member::Named(ident.clone())), + None => (i.to_string(), syn::Member::Unnamed(i.into())), + }; + + let attrs = BindgenAttrs::find(&mut field.attrs)?; + assert_not_variadic(&attrs)?; + if attrs.skip().is_some() { + attrs.check_used()?; + continue; + } + + let comments = extract_doc_comments(&field.attrs); + let getter = shared::struct_field_get(&js_name, &name_str); + let setter = shared::struct_field_set(&js_name, &name_str); + + fields.push(ast::StructField { + name: member, + struct_name: self.ident.clone(), + readonly: attrs.readonly().is_some(), + ty: field.ty.clone(), + getter: Ident::new(&getter, Span::call_site()), + setter: Ident::new(&setter, Span::call_site()), + comments, + }); + attrs.check_used()?; } let comments: Vec = extract_doc_comments(&self.attrs); attrs.check_used()?; diff --git a/tests/wasm/classes.js b/tests/wasm/classes.js index 995e87dd..86de4727 100644 --- a/tests/wasm/classes.js +++ b/tests/wasm/classes.js @@ -137,6 +137,7 @@ exports.js_js_rename = () => { exports.js_access_fields = () => { assert.ok((new wasm.AccessFieldFoo()).bar instanceof wasm.AccessFieldBar); + assert.ok((new wasm.AccessField0())[0] instanceof wasm.AccessFieldBar); }; exports.js_renamed_export = () => { diff --git a/tests/wasm/classes.rs b/tests/wasm/classes.rs index be167058..ee904c05 100644 --- a/tests/wasm/classes.rs +++ b/tests/wasm/classes.rs @@ -369,6 +369,9 @@ pub struct AccessFieldFoo { pub bar: AccessFieldBar, } +#[wasm_bindgen] +pub struct AccessField0(pub AccessFieldBar); + #[wasm_bindgen] #[derive(Copy, Clone)] pub struct AccessFieldBar { @@ -385,6 +388,14 @@ impl AccessFieldFoo { } } +#[wasm_bindgen] +impl AccessField0 { + #[wasm_bindgen(constructor)] + pub fn new() -> AccessField0 { + AccessField0(AccessFieldBar { _value: 2 }) + } +} + #[wasm_bindgen_test] fn access_fields() { js_access_fields();