picodata_plugin_proc_macro/
lib.rs

1extern crate proc_macro;
2use proc_macro::TokenStream;
3
4use quote::quote;
5use syn::{parse_macro_input, ReturnType, Signature};
6
7#[proc_macro_attribute]
8pub fn proc_service_registrar(_attr: TokenStream, input: TokenStream) -> TokenStream {
9    let input = parse_macro_input!(input as syn::Item);
10
11    let syn::ItemFn { sig, block, .. } = match input {
12        syn::Item::Fn(f) => f,
13        _ => panic!("only `fn` items allowed"),
14    };
15
16    let (ident, inputs, _generics) = match sig {
17        Signature {
18            asyncness: Some(_), ..
19        } => {
20            panic!("async factory are not supported yet")
21        }
22        Signature {
23            variadic: Some(_), ..
24        } => {
25            panic!("variadic factory are not supported yet")
26        }
27        Signature {
28            ident,
29            output,
30            inputs,
31            generics,
32            ..
33        } => {
34            if !matches!(output, ReturnType::Default) {
35                panic!("function must have no output")
36            }
37
38            if inputs.len() != 1 {
39                panic!("there is only 1 input argument supported")
40            }
41
42            (ident, inputs, generics)
43        }
44    };
45
46    let inner_fn_name =
47        syn::Ident::new(&("__inner_".to_string() + &ident.to_string()), ident.span());
48
49    // embeds function for check input argument
50    quote! {
51        #[export_name = "pico_service_registrar"]
52        pub extern "C" fn #ident(registry: &mut picodata_plugin::plugin::interface::ServiceRegistry) {
53            #[inline(always)]
54            fn #inner_fn_name (#inputs) {
55                picodata_plugin::internal::set_panic_hook();
56
57                #block
58            }
59
60            #inner_fn_name(registry)
61        }
62    }
63    .into()
64}