use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{ItemFn, ReturnType, parse_macro_input};
#[proc_macro_attribute]
pub fn into_actor_result(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input_fn = parse_macro_input!(item as ItemFn);
let mut do_fn = input_fn.clone();
let fn_name = &input_fn.sig.ident;
let do_fn_name = format_ident!("do_{}", fn_name);
do_fn.sig.ident = do_fn_name.clone();
do_fn.vis = syn::Visibility::Inherited;
let vis = &input_fn.vis;
let asyncness = &input_fn.sig.asyncness;
let generics = &input_fn.sig.generics;
let inputs = &input_fn.sig.inputs;
let return_type = match &input_fn.sig.output {
ReturnType::Default => quote! { () },
ReturnType::Type(_, ty) => quote! { #ty },
};
let arg_names = inputs
.iter()
.filter_map(|arg| {
if let syn::FnArg::Typed(pat_type) = arg
&& let syn::Pat::Ident(pat_ident) = &*pat_type.pat
&& pat_ident.ident != "self"
{
return Some(&pat_ident.ident);
}
None
})
.collect::<Vec<_>>();
let awaiter = asyncness.is_some().then(|| quote!(.await));
let wrapper_fn = quote! {
#vis async fn #fn_name #generics (#inputs) -> act_zero::ActorResult<#return_type> {
let result = self.#do_fn_name(#(#arg_names),*) #awaiter;
act_zero::Produces::ok(result)
}
};
let result = quote! {
#wrapper_fn
#do_fn
};
result.into()
}