use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, Expr, ItemFn};
#[cfg(feature = "anyhow")]
#[proc_macro_attribute]
pub fn anyhow(attr: TokenStream, item: TokenStream) -> TokenStream {
wrap_with(attr, item, quote! { anyhow })
}
#[allow(unused)]
fn wrap_with(
attr: TokenStream,
item: TokenStream,
crate_: proc_macro2::TokenStream,
) -> TokenStream {
use syn::{punctuated::Punctuated, token::Comma, FnArg};
let input = parse_macro_input!(item as ItemFn);
let create_message = parse_macro_input!(attr as Expr);
let sig = &input.sig;
let args = input
.sig
.inputs
.iter()
.map(|arg| match arg {
FnArg::Receiver(r) => {
let self_ = &r.self_token;
quote! { #self_ }
}
FnArg::Typed(typed) => {
let pat = &typed.pat;
quote! { #pat }
}
})
.collect::<Punctuated<_, Comma>>();
let do_create = match &create_message {
Expr::Closure(c) => {
let args = args
.iter()
.map(|a| quote! { &#a })
.collect::<Punctuated<_, Comma>>();
quote! { (#c)(#args) }
}
e => e.to_token_stream(),
};
let block = &input.block;
let vis = &input.vis;
let inner = match &input.sig.asyncness {
Some(_) => quote! { async #block.await },
None => quote! { (|| #block)() },
};
let expanded = quote! {
#vis #sig {
let message = #do_create;
let inner: #crate_::Result<_> = #inner;
match inner {
Ok(t) => Ok(t),
Err(e) => {
#crate_::Context::<_, _>::context(Err(e), message)
}
}
}
};
TokenStream::from(expanded)
}
#[cfg(feature = "eyre")]
#[proc_macro_attribute]
pub fn eyre(attr: TokenStream, item: TokenStream) -> TokenStream {
wrap_with(attr, item, quote! { eyre })
}