1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, ItemFn};
4
5#[proc_macro_attribute]
17pub fn app(_attr: TokenStream, item: TokenStream) -> TokenStream {
18 let input = parse_macro_input!(item as ItemFn);
19 let fn_name = &input.sig.ident;
20 let fn_block = &input.block;
21 let fn_vis = &input.vis;
22
23 let expanded = quote! {
24 #fn_vis fn #fn_name(ui: &mut rustview::ui::Ui) {
25 #fn_block
26 }
27 };
28
29 TokenStream::from(expanded)
30}
31
32#[proc_macro_attribute]
50pub fn cached(_attr: TokenStream, item: TokenStream) -> TokenStream {
51 let input = parse_macro_input!(item as ItemFn);
52 let fn_name = &input.sig.ident;
53 let fn_vis = &input.vis;
54 let fn_sig = &input.sig;
55 let fn_block = &input.block;
56 let fn_output = &fn_sig.output;
57 let fn_inputs = &fn_sig.inputs;
58
59 let fn_name_str = fn_name.to_string();
60
61 let param_names: Vec<_> = fn_inputs
63 .iter()
64 .filter_map(|arg| {
65 if let syn::FnArg::Typed(pat_type) = arg {
66 if let syn::Pat::Ident(pat_ident) = pat_type.pat.as_ref() {
67 return Some(pat_ident.ident.clone());
68 }
69 }
70 None
71 })
72 .collect();
73
74 let expanded = quote! {
75 #fn_vis fn #fn_name(#fn_inputs) #fn_output {
76 use std::hash::{Hash, Hasher};
77
78 let mut hasher = fnv::FnvHasher::default();
79 #fn_name_str.hash(&mut hasher);
80 #( #param_names.hash(&mut hasher); )*
81 let cache_key = hasher.finish();
82
83 if let Some(cached) = rustview::cache::get_cached::<_>(#fn_name_str, cache_key) {
85 return cached;
86 }
87
88 let result = (|| #fn_block)();
89
90 rustview::cache::insert_cached(#fn_name_str, cache_key, result.clone());
91
92 result
93 }
94 };
95
96 TokenStream::from(expanded)
97}