chrome_native_macros/
lib.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput};
4
5#[proc_macro_attribute]
6pub fn chrome_native_task(
7    _metadata: proc_macro::TokenStream,
8    input: proc_macro::TokenStream,
9) -> proc_macro::TokenStream {
10    let input: TokenStream = input.into();
11
12    let expanded = quote! {
13        #[derive(serde::Serialize, serde::Deserialize)]
14        #[serde(tag = "task", content = "message")]
15        #input
16    };
17
18    expanded.into()
19}
20
21#[proc_macro_attribute]
22pub fn chrome_native_data(
23    _metadata: proc_macro::TokenStream,
24    input: proc_macro::TokenStream,
25) -> proc_macro::TokenStream {
26    let input: TokenStream = input.into();
27
28    let expanded = quote! {
29        #[derive(serde::Serialize, serde::Deserialize)]
30        #input
31    };
32
33    expanded.into()
34}
35
36fn generator(ast: &DeriveInput) -> TokenStream {
37    let name = &ast.ident;
38
39    if let syn::Data::Struct(syn::DataStruct {
40        fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }),
41        ..
42    }) = ast.data
43    {
44        if ast.attrs.len() != 0 {
45            let default_gen: syn::LitBool = ast.attrs[0].parse_args().unwrap();
46            let generate = default_gen.value();
47            if generate {
48                let all_option = named.iter().all(|f| {
49                    if let syn::Type::Path(ref p) = f.ty {
50                        p.path.segments.len() == 1 && p.path.segments[0].ident == "Option"
51                    } else {
52                        false
53                    }
54                });
55                if all_option {
56                    let options_value = named.iter().map(|f| {
57                        let name = &f.ident;
58                        quote! {
59                            #name: None
60                        }
61                    });
62                    return quote! {
63                        impl #name {
64                            fn create_self() -> Self {
65                                Self {
66                                    #(#options_value,)*
67                                }
68                            }
69                        }
70                    }
71                    .into();
72                }
73            }
74        }
75    }
76    quote! {}.into()
77}
78
79#[proc_macro_derive(Plugin, attributes(default_gen))]
80pub fn plugin_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
81    let ast = parse_macro_input!(input as DeriveInput);
82    let name = &ast.ident;
83    let generated = &generator(&ast);
84
85    let expanded = quote! {
86        #generated
87
88        #[no_mangle]
89        pub extern fn get_plugin() -> *mut dyn chrome_native::Plugin {
90            Box::into_raw(Box::new(#name::create_self()))
91        }
92    };
93
94    expanded.into()
95}