Skip to content

Commit b610c3f

Browse files
committed
fix: Fix cfg_attr in struct declaration
1 parent 7fa2afa commit b610c3f

File tree

5 files changed

+86
-17
lines changed

5 files changed

+86
-17
lines changed

crates/macro-support/src/lib.rs

+51-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extern crate wasm_bindgen_backend as backend;
1212
extern crate wasm_bindgen_shared as shared;
1313

1414
pub use crate::parser::BindgenAttrs;
15-
use crate::parser::MacroParse;
15+
use crate::parser::{ConvertToAst, MacroParse};
1616
use backend::{Diagnostic, TryToTokens};
1717
use proc_macro2::TokenStream;
1818
use quote::ToTokens;
@@ -24,7 +24,41 @@ mod parser;
2424
/// Takes the parsed input from a `#[wasm_bindgen]` macro and returns the generated bindings
2525
pub fn expand(attr: TokenStream, input: TokenStream) -> Result<TokenStream, Diagnostic> {
2626
parser::reset_attrs_used();
27+
// if struct is encountered, add `derive` attribute and let everything happen there (workaround
28+
// to help parsing cfg_attr correctly).
2729
let item = syn::parse2::<syn::Item>(input)?;
30+
if let syn::Item::Struct(mut s) = item {
31+
s.attrs.insert(
32+
0,
33+
syn::Attribute {
34+
pound_token: Default::default(),
35+
style: syn::AttrStyle::Outer,
36+
bracket_token: Default::default(),
37+
meta: syn::parse_quote! {
38+
derive(wasm_bindgen::prelude::BindgenedStruct)
39+
},
40+
},
41+
);
42+
if !attr.is_empty() {
43+
let meta: syn::Meta = syn::parse2(attr)?;
44+
s.attrs.insert(
45+
1,
46+
syn::Attribute {
47+
pound_token: Default::default(),
48+
style: syn::AttrStyle::Outer,
49+
bracket_token: Default::default(),
50+
meta: syn::parse_quote! {
51+
wasm_bindgen(#meta)
52+
},
53+
},
54+
);
55+
}
56+
57+
let mut tokens = proc_macro2::TokenStream::new();
58+
s.to_tokens(&mut tokens);
59+
return Ok(tokens);
60+
}
61+
2862
let opts = syn::parse2(attr)?;
2963

3064
let mut tokens = proc_macro2::TokenStream::new();
@@ -168,3 +202,19 @@ impl Parse for ClassMarker {
168202
})
169203
}
170204
}
205+
206+
pub fn expand_struct_marker(item: TokenStream) -> Result<TokenStream, Diagnostic> {
207+
parser::reset_attrs_used();
208+
209+
let mut s: syn::ItemStruct = syn::parse2(item)?;
210+
211+
let mut program = backend::ast::Program::default();
212+
program.structs.push((&mut s).convert(&program)?);
213+
214+
let mut tokens = proc_macro2::TokenStream::new();
215+
program.try_to_tokens(&mut tokens)?;
216+
217+
parser::check_unused_attrs(&mut tokens);
218+
219+
Ok(tokens)
220+
}

crates/macro-support/src/parser.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ impl Parse for AnyIdent {
413413
///
414414
/// Used to convert syn tokens into an AST, that we can then use to generate glue code. The context
415415
/// (`Ctx`) is used to pass in the attributes from the `#[wasm_bindgen]`, if needed.
416-
trait ConvertToAst<Ctx> {
416+
pub(crate) trait ConvertToAst<Ctx> {
417417
/// What we are converting to.
418418
type Target;
419419
/// Convert into our target.
@@ -422,27 +422,27 @@ trait ConvertToAst<Ctx> {
422422
fn convert(self, context: Ctx) -> Result<Self::Target, Diagnostic>;
423423
}
424424

425-
impl ConvertToAst<(&ast::Program, BindgenAttrs)> for &mut syn::ItemStruct {
425+
impl ConvertToAst<&ast::Program> for &mut syn::ItemStruct {
426426
type Target = ast::Struct;
427427

428-
fn convert(
429-
self,
430-
(program, attrs): (&ast::Program, BindgenAttrs),
431-
) -> Result<Self::Target, Diagnostic> {
428+
fn convert(self, program: &ast::Program) -> Result<Self::Target, Diagnostic> {
432429
if !self.generics.params.is_empty() {
433430
bail_span!(
434431
self.generics,
435432
"structs with #[wasm_bindgen] cannot have lifetime or \
436433
type parameters currently"
437434
);
438435
}
436+
let struct_attrs = BindgenAttrs::find(&mut self.attrs)?;
437+
439438
let mut fields = Vec::new();
440-
let js_name = attrs
439+
let js_name = struct_attrs
441440
.js_name()
442441
.map(|s| s.0.to_string())
443442
.unwrap_or(self.ident.unraw().to_string());
444-
let is_inspectable = attrs.inspectable().is_some();
445-
let getter_with_clone = attrs.getter_with_clone();
443+
let is_inspectable = struct_attrs.inspectable().is_some();
444+
let getter_with_clone = struct_attrs.getter_with_clone();
445+
446446
for (i, field) in self.fields.iter_mut().enumerate() {
447447
match field.vis {
448448
syn::Visibility::Public(..) => {}
@@ -484,9 +484,9 @@ impl ConvertToAst<(&ast::Program, BindgenAttrs)> for &mut syn::ItemStruct {
484484
});
485485
attrs.check_used();
486486
}
487-
let generate_typescript = attrs.skip_typescript().is_none();
487+
let generate_typescript = struct_attrs.skip_typescript().is_none();
488488
let comments: Vec<String> = extract_doc_comments(&self.attrs);
489-
attrs.check_used();
489+
struct_attrs.check_used();
490490
Ok(ast::Struct {
491491
rust_name: self.ident.clone(),
492492
js_name,
@@ -1159,11 +1159,6 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
11591159
wasm_bindgen_futures: program.wasm_bindgen_futures.clone(),
11601160
});
11611161
}
1162-
syn::Item::Struct(mut s) => {
1163-
let opts = opts.unwrap_or_default();
1164-
program.structs.push((&mut s).convert((program, opts))?);
1165-
s.to_tokens(tokens);
1166-
}
11671162
syn::Item::Impl(mut i) => {
11681163
let opts = opts.unwrap_or_default();
11691164
(&mut i).macro_parse(program, opts)?;

crates/macro/src/lib.rs

+13
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,16 @@ pub fn __wasm_bindgen_class_marker(attr: TokenStream, input: TokenStream) -> Tok
7171
Err(diagnostic) => (quote! { #diagnostic }).into(),
7272
}
7373
}
74+
75+
#[proc_macro_derive(BindgenedStruct, attributes(wasm_bindgen))]
76+
pub fn __wasm_bindgen_struct_marker(item: TokenStream) -> TokenStream {
77+
match wasm_bindgen_macro_support::expand_struct_marker(item.into()) {
78+
Ok(tokens) => {
79+
if cfg!(feature = "xxx_debug_only_print_generated_code") {
80+
println!("{}", tokens);
81+
}
82+
tokens.into()
83+
}
84+
Err(diagnostic) => (quote! { #diagnostic }).into(),
85+
}
86+
}

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ pub mod prelude {
6363
pub use crate::JsCast;
6464
pub use crate::JsValue;
6565
pub use crate::UnwrapThrowExt;
66+
pub use wasm_bindgen_macro::BindgenedStruct;
6667
#[doc(hidden)]
6768
pub use wasm_bindgen_macro::__wasm_bindgen_class_marker;
6869
pub use wasm_bindgen_macro::wasm_bindgen;

tests/wasm/classes.rs

+10
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,16 @@ fn renamed_field() {
480480
js_renamed_field();
481481
}
482482

483+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
484+
pub struct ConditionalSkip {
485+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
486+
pub skipped_field: [u8; 8],
487+
488+
/// cfg_attr annotated field
489+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(getter_with_clone))]
490+
pub needs_clone: String,
491+
}
492+
483493
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
484494
pub struct ConditionalBindings {}
485495

0 commit comments

Comments
 (0)