#![feature(proc_macro_diagnostic)]
use proc_macro::TokenStream;
use quote::quote;
use syn::parse_macro_input;
use syn::spanned::Spanned;
use syn;
#[proc_macro_attribute]
pub fn mula(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut mula_fn = parse_macro_input!(input as syn::ItemFn);
let original_ident = mula_fn.sig.ident.clone();
let wrapped_ident = syn::Ident::new(
format!("{}_mula_fn", original_ident).as_str(),
original_ident.span()
);
mula_fn.sig.ident = wrapped_ident.clone();
let mula_ident = syn::Ident::new(
format!("static_mula_for_{}", original_ident).to_uppercase().as_str(),
original_ident.span()
);
let input_type = if let syn::FnArg::Typed(pat) = mula_fn.sig.inputs.first().unwrap() {
&*pat.ty
} else {
return syn::Error::new(mula_fn.sig.span(), "mula functions must accept a single argument").to_compile_error().into();
};
let return_type = if let syn::ReturnType::Type(_, ty) = &mula_fn.sig.output {
&**ty
} else {
return syn::Error::new(mula_fn.sig.span(), "mula functions must return a single value").to_compile_error().into();
};
let result = quote! {
#mula_fn
static #mula_ident: ::mula::once_cell::sync::OnceCell<std::sync::Arc<mula::Mula<#input_type, #return_type, &'static (dyn Fn(#input_type) -> #return_type + Sync)>>> = ::mula::once_cell::sync::OnceCell::new();
fn #original_ident(input: #input_type) -> #return_type {
let m = #mula_ident.get_or_init(|| {
::mula::Mula::new(&#wrapped_ident)
});
let result = ::mula::Mula::subscribe_to(m.clone(), input.clone());
result
}
};
result.into()
}