mu_sdk_macros/
lib.rs

1use quote::quote;
2use syn::ItemFn;
3
4#[proc_macro_attribute]
5pub fn public(
6    _attr: proc_macro::TokenStream,
7    item: proc_macro::TokenStream,
8) -> proc_macro::TokenStream {
9    let module = syn::parse_macro_input!(item as syn::ItemMod);
10
11    let mod_ident = &module.ident; // Module name
12    let mut new_content = Vec::new();
13
14    // Iterate over all items in the module
15    if let Some((_, items)) = &module.content {
16        for item in items {
17            if let syn::Item::Fn(func) = item {
18                // Process each function
19                new_content.push(process_function(func));
20            } else {
21                // Keep non-function items as they are
22                new_content.push(quote! { #item });
23            }
24        }
25    }
26
27    // Reconstruct the module
28    quote! {
29        mod #mod_ident {
30            #( #new_content )*
31        }
32
33        ic_cdk::export_candid!();
34    }
35    .into()
36}
37
38fn process_function(func: &ItemFn) -> proc_macro2::TokenStream {
39    let mut transformed_func = func.clone();
40
41    let has_function_attr = func
42        .attrs
43        .iter()
44        .any(|attr| attr.path().is_ident("function"));
45    if has_function_attr {
46        // add the ic_cdk attribute to the function and remove the function attribute
47        transformed_func
48            .attrs
49            .push(syn::parse_quote!(#[ic_cdk::update]));
50        transformed_func
51            .attrs
52            .retain(|attr| !attr.path().is_ident("function"));
53    }
54
55    // Convert the function back into a token stream
56    quote! {
57        #transformed_func
58    }
59}