1use darling::{ast::NestedMeta, error::Accumulator};
2use quote::quote;
3use syn::{Ident, ItemFn, parse_macro_input, spanned::Spanned};
4
5#[proc_macro_attribute]
7pub fn call_on_init(
8 args: proc_macro::TokenStream,
9 input: proc_macro::TokenStream,
10) -> proc_macro::TokenStream {
11 let mut errors = Accumulator::default();
12
13 let attr_args = match NestedMeta::parse_meta_list(args.into()) {
14 Ok(v) => v,
15 Err(err) => {
16 return darling::Error::from(err).write_errors().into();
17 }
18 };
19
20 for nested_meta in attr_args {
21 errors.push(darling::Error::custom("args not supported").with_span(&nested_meta.span()));
22 }
23
24 let input = parse_macro_input!(input as ItemFn);
25
26 if input.sig.asyncness.is_some() {
27 errors.push(
28 darling::Error::custom(
29 "the `async` keywork cannot be used on the function declaration",
30 )
31 .with_span(&input.sig.fn_token.span()),
32 );
33 }
34
35 if let Err(err) = errors.finish() {
36 return err.write_errors().into();
37 }
38
39 let ident = input.sig.ident.clone();
40 let static_ident = Ident::new(&ident.to_string().to_uppercase(), ident.span());
41
42 let expanded = quote! {
43 #[init_hook::linkme::distributed_slice(init_hook::__private::INIT_FNS)]
44 #[linkme(crate = init_hook::linkme)]
45 static #static_ident: fn() = #ident;
46
47 #input
48 };
49
50 expanded.into()
51}