wasm_bindgen_duck_type_macro_impl/
lib.rs1extern crate proc_macro;
4
5use proc_macro::TokenStream;
6use quote::{format_ident, quote};
7use syn;
8
9#[proc_macro_attribute]
11pub fn wasm_bindgen_duck_type(_attr: TokenStream, item: TokenStream) -> TokenStream {
12 let ast = syn::parse(item).unwrap();
13
14 impl_duck_type(&ast)
15}
16
17fn impl_duck_type(item_struct: &syn::ItemStruct) -> TokenStream {
18 let name = &item_struct.ident;
19 let vis = &item_struct.vis;
20 let fields = &item_struct.fields;
21 if let syn::Fields::Named(feilds) = fields {
22 let field_methods = feilds.named.iter().map(|x| {
23 let f_name = x.ident.as_ref().unwrap();
24 let f_type = &x.ty;
25
26 let f_setter_name = format_ident!("set_{}", f_name);
27
28 quote! {
29 #[::wasm_bindgen::prelude::wasm_bindgen(method, getter)]
30 #vis fn #f_name(this: &#name) -> #f_type;
31 #[::wasm_bindgen::prelude::wasm_bindgen(method, setter)]
32 #vis fn #f_setter_name(this: &#name, val: #f_type);
33 }
34 });
35
36 let signature = feilds.named.iter().map(|x| {
37 let f_name = x.ident.as_ref().unwrap();
38 let f_type = &x.ty;
39
40 quote! {
41 #f_name: #f_type
42 }
43 });
44
45 let new_impl = feilds.named.iter().map(|x| {
46 let f_name = x.ident.as_ref().unwrap();
47 let prop = format_ident!("set_{}", f_name);
48
49 quote! {
50 new.#prop(#f_name);
51 }
52 });
53
54 let gen = quote! {
55 #[::wasm_bindgen::prelude::wasm_bindgen(method, getter)]
56 extern "C" {
57 #vis type #name;
58
59 #(#field_methods)*
60 }
61
62 impl #name {
63 pub fn new(#(#signature),*) -> Self {
64 let new: Self = Self::default();
65
66 #(#new_impl)*
67
68 new
69 }
70 }
71
72 impl ::std::default::Default for #name {
73 fn default() -> Self {
74 JsValue::from(js_sys::Object::new()).into()
75 }
76 }
77 };
78
79 gen.into()
80 } else {
81 panic!("Expand macro can only be used on named structs");
82 }
83}