wasm_bindgen_duck_type_macro_impl/
lib.rs

1//! Implementation for [wasm_bindgen_duck_type](https://docs.rs/wasm_bindgen_duck_type)
2
3extern crate proc_macro;
4
5use proc_macro::TokenStream;
6use quote::{format_ident, quote};
7use syn;
8
9/// Attribute macro to generate duck type interface
10#[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}