1use proc_macro::TokenStream;
6use quote::quote;
7use syn::{parse_macro_input, punctuated::Punctuated, ItemFn, Meta, Token};
8
9#[proc_macro_attribute]
25pub fn rmlx_kernel(attr: TokenStream, item: TokenStream) -> TokenStream {
26 let input = parse_macro_input!(item as ItemFn);
27 let attrs = parse_macro_input!(attr with Punctuated::<Meta, Token![,]>::parse_terminated);
28
29 let fn_name = &input.sig.ident;
30
31 if input.sig.inputs.len() != 1 {
33 return syn::Error::new_spanned(
34 &input.sig,
35 "rmlx_kernel: expected exactly one parameter (registry: &KernelRegistry)",
36 )
37 .to_compile_error()
38 .into();
39 }
40
41 let mut kernel_name: Option<String> = None;
43 for meta in &attrs {
44 if let Meta::NameValue(nv) = meta {
45 if nv.path.is_ident("name") {
46 if let syn::Expr::Lit(syn::ExprLit {
47 lit: syn::Lit::Str(s),
48 ..
49 }) = &nv.value
50 {
51 kernel_name = Some(s.value());
52 }
53 }
54 }
55 }
56
57 let kernel_name_str = kernel_name.unwrap_or_else(|| fn_name.to_string());
58 let metadata_fn_name = syn::Ident::new(&format!("{fn_name}_kernel_metadata"), fn_name.span());
59
60 let output = quote! {
61 #input
62
63 #[doc(hidden)]
65 pub fn #metadata_fn_name() -> &'static str {
66 #kernel_name_str
67 }
68 };
69
70 output.into()
71}