|
1 | 1 | use proc_macro::TokenStream; |
2 | 2 | use quote::{format_ident, quote}; |
3 | | -use syn::{Expr, ItemFn, ItemStatic, ReturnType, parse_macro_input}; |
| 3 | +use syn::{Expr, Ident, ItemFn, ItemStatic, ReturnType, parse_macro_input}; |
4 | 4 |
|
5 | 5 | #[proc_macro] |
6 | 6 | pub fn signal(input: TokenStream) -> TokenStream { |
@@ -127,3 +127,53 @@ pub fn effect(input: TokenStream) -> TokenStream { |
127 | 127 |
|
128 | 128 | expanded.into() |
129 | 129 | } |
| 130 | + |
| 131 | +#[proc_macro_attribute] |
| 132 | +pub fn evaluate(attr: TokenStream, item: TokenStream) -> TokenStream { |
| 133 | + let print = parse_macro_input!(attr as Ident); |
| 134 | + let func = parse_macro_input!(item as ItemFn); |
| 135 | + |
| 136 | + let vis = &func.vis; |
| 137 | + let sig = &func.sig; |
| 138 | + let block = &func.block; |
| 139 | + let ident = &func.sig.ident; |
| 140 | + |
| 141 | + let output_ty = match &sig.output { |
| 142 | + ReturnType::Type(_, ty) => ty.clone(), |
| 143 | + _ => { |
| 144 | + return syn::Error::new_spanned(&sig.output, "Functions must have a return value") |
| 145 | + .to_compile_error() |
| 146 | + .into(); |
| 147 | + } |
| 148 | + }; |
| 149 | + |
| 150 | + if !sig.inputs.is_empty() { |
| 151 | + return syn::Error::new_spanned( |
| 152 | + &sig.inputs, |
| 153 | + "The memo macro can only be used with `get` function without any parameters.", |
| 154 | + ) |
| 155 | + .to_compile_error() |
| 156 | + .into(); |
| 157 | + } |
| 158 | + |
| 159 | + let option_ty = quote! { Option<#output_ty> }; |
| 160 | + let ident = ident.to_string(); |
| 161 | + |
| 162 | + let expanded = quote! { |
| 163 | + #vis #sig |
| 164 | + where #output_ty: Eq + Clone + 'static |
| 165 | + { |
| 166 | + let new: #output_ty = (|| #block)(); |
| 167 | + |
| 168 | + static mut VALUE: #option_ty = None; |
| 169 | + if let Some(old) = unsafe { VALUE } && old == new { |
| 170 | + #print(format!("Evaluate: {} not changed, still {:?}\n", #ident, new)); |
| 171 | + } |
| 172 | + unsafe { VALUE = Some(new.clone()) }; |
| 173 | + |
| 174 | + new |
| 175 | + } |
| 176 | + }; |
| 177 | + |
| 178 | + expanded.into() |
| 179 | +} |
0 commit comments