wasm_bindgen_macro_support/
lib.rs1#![doc(html_root_url = "https://docs.rs/wasm-bindgen-macro-support/0.2")]
4
5#[macro_use]
6mod error;
7
8mod ast;
9mod codegen;
10mod encode;
11mod generics;
12mod hash;
13mod parser;
14
15use codegen::TryToTokens;
16use error::Diagnostic;
17pub use parser::BindgenAttrs;
18use parser::{ConvertToAst, MacroParse};
19use proc_macro2::TokenStream;
20use quote::quote;
21use quote::ToTokens;
22use quote::TokenStreamExt;
23use syn::parse::{Parse, ParseStream, Result as SynResult};
24use syn::Token;
25
26pub fn expand(attr: TokenStream, input: TokenStream) -> Result<TokenStream, Diagnostic> {
28 parser::reset_attrs_used();
29 let item = syn::parse2::<syn::Item>(input)?;
32 if let syn::Item::Struct(s) = item {
33 let opts: BindgenAttrs = syn::parse2(attr.clone())?;
34 let wasm_bindgen = opts
35 .wasm_bindgen()
36 .cloned()
37 .unwrap_or_else(|| syn::parse_quote! { ::wasm_bindgen });
38
39 let item = quote! {
40 #[derive(#wasm_bindgen::__rt::BindgenedStruct)]
41 #[wasm_bindgen(#attr)]
42 #s
43 };
44 return Ok(item);
45 }
46
47 let opts = syn::parse2(attr)?;
48 let mut tokens = proc_macro2::TokenStream::new();
49 let mut program = ast::Program::default();
50 item.macro_parse(&mut program, (Some(opts), &mut tokens))?;
51 program.try_to_tokens(&mut tokens)?;
52
53 parser::check_unused_attrs(&mut tokens);
57
58 Ok(tokens)
59}
60
61pub fn expand_link_to(input: TokenStream) -> Result<TokenStream, Diagnostic> {
63 parser::reset_attrs_used();
64 let opts = syn::parse2(input)?;
65
66 let mut tokens = proc_macro2::TokenStream::new();
67 let link = parser::link_to(opts)?;
68 link.try_to_tokens(&mut tokens)?;
69
70 Ok(tokens)
71}
72
73pub fn expand_class_marker(
75 attr: TokenStream,
76 input: TokenStream,
77) -> Result<TokenStream, Diagnostic> {
78 parser::reset_attrs_used();
79 let mut item = syn::parse2::<syn::ImplItemFn>(input)?;
80 let opts: ClassMarker = syn::parse2(attr)?;
81
82 let mut program = ast::Program::default();
83 item.macro_parse(&mut program, &opts)?;
84
85 let mut tokens = proc_macro2::TokenStream::new();
97 tokens.append_all(
98 item.attrs
99 .iter()
100 .filter(|attr| matches!(attr.style, syn::AttrStyle::Outer)),
101 );
102 item.vis.to_tokens(&mut tokens);
103 item.sig.to_tokens(&mut tokens);
104 let mut err = None;
105 item.block.brace_token.surround(&mut tokens, |tokens| {
106 if let Err(e) = program.try_to_tokens(tokens) {
107 err = Some(e);
108 }
109 parser::check_unused_attrs(tokens); tokens.append_all(
111 item.attrs
112 .iter()
113 .filter(|attr| matches!(attr.style, syn::AttrStyle::Inner(_))),
114 );
115 tokens.append_all(&item.block.stmts);
116 });
117
118 if let Some(err) = err {
119 return Err(err);
120 }
121
122 Ok(tokens)
123}
124
125struct ClassMarker {
126 class: syn::Ident,
127 js_class: String,
128 wasm_bindgen: syn::Path,
129 wasm_bindgen_futures: syn::Path,
130}
131
132impl Parse for ClassMarker {
133 fn parse(input: ParseStream) -> SynResult<Self> {
134 let class = input.parse::<syn::Ident>()?;
135 input.parse::<Token![=]>()?;
136 let mut js_class = input.parse::<syn::LitStr>()?.value();
137 js_class = js_class
138 .strip_prefix("r#")
139 .map(String::from)
140 .unwrap_or(js_class);
141
142 let mut wasm_bindgen = None;
143 let mut wasm_bindgen_futures = None;
144
145 loop {
146 if input.parse::<Option<Token![,]>>()?.is_some() {
147 let ident = input.parse::<syn::Ident>()?;
148
149 if ident == "wasm_bindgen" {
150 if wasm_bindgen.is_some() {
151 return Err(syn::Error::new(
152 ident.span(),
153 "found duplicate `wasm_bindgen`",
154 ));
155 }
156
157 input.parse::<Token![=]>()?;
158 wasm_bindgen = Some(input.parse::<syn::Path>()?);
159 } else if ident == "wasm_bindgen_futures" {
160 if wasm_bindgen_futures.is_some() {
161 return Err(syn::Error::new(
162 ident.span(),
163 "found duplicate `wasm_bindgen_futures`",
164 ));
165 }
166
167 input.parse::<Token![=]>()?;
168 wasm_bindgen_futures = Some(input.parse::<syn::Path>()?);
169 } else {
170 return Err(syn::Error::new(
171 ident.span(),
172 "expected `wasm_bindgen` or `wasm_bindgen_futures`",
173 ));
174 }
175 } else {
176 break;
177 }
178 }
179
180 Ok(ClassMarker {
181 class,
182 js_class,
183 wasm_bindgen: wasm_bindgen.unwrap_or_else(|| syn::parse_quote! { wasm_bindgen }),
184 wasm_bindgen_futures: wasm_bindgen_futures
185 .unwrap_or_else(|| syn::parse_quote! { wasm_bindgen_futures }),
186 })
187 }
188}
189
190pub fn expand_struct_marker(item: TokenStream) -> Result<TokenStream, Diagnostic> {
191 parser::reset_attrs_used();
192
193 let mut s: syn::ItemStruct = syn::parse2(item)?;
194
195 let mut program = ast::Program::default();
196 program.structs.push((&mut s).convert(&program)?);
197
198 let mut tokens = proc_macro2::TokenStream::new();
199 program.try_to_tokens(&mut tokens)?;
200
201 parser::check_unused_attrs(&mut tokens);
202
203 Ok(tokens)
204}