1#![warn(missing_docs)]
2
3use proc_macro::TokenStream;
6use quote::{format_ident, quote};
7use syn::parse::*;
8use syn::punctuated::*;
9use syn::*;
10
11struct Name(String);
12
13impl Parse for Name {
14 fn parse(input: ParseStream) -> Result<Self> {
15 let name = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
16 assert!(name.len() == 1, "set_entry macro takes one argument");
17 Ok(Self(name[0].to_string()))
18 }
19}
20
21#[proc_macro_attribute]
23pub fn set_entry(meta: TokenStream, decl: TokenStream) -> TokenStream {
24 let meta = parse_macro_input!(meta as Name);
25 let decl = parse_macro_input!(decl as ItemStatic);
26
27 let set = meta.0;
28 let set_section = format!("set_{}", set);
29 let set_ident = format_ident!("{}", set);
30 let start_set = format_ident!("__start_set_{}", set);
31 let fn_name = format_ident!(
32 "__set_{}_typecheck_{}",
33 set,
34 decl.ident.to_string().to_lowercase()
35 );
36 let expr = decl.expr.clone();
37
38 let g = quote! {
39 #[unsafe(link_section = #set_section)]
40 #[used]
41 #decl
42
43 #[cfg(any(debug_assertions, test))]
44 #[allow(unused)]
45 fn #fn_name() -> bool {
46 #[allow(clippy::fn_address_comparisons)]
48 unsafe { #set_ident::#start_set == #expr }
49 }
50 };
51 TokenStream::from(g)
52}