infinite_errors_macros/
lib.rs1extern crate proc_macro;
2
3#[cfg(test)]
4mod test;
5
6use proc_macro::TokenStream;
7use quote::{quote, ToTokens};
8use syn::{parse_quote, ItemFn, TypePath};
9
10#[proc_macro_attribute]
24pub fn err_context(attributes: TokenStream, item: TokenStream) -> TokenStream {
25 err_context_impl(attributes.into(), item.into()).into()
26}
27
28fn err_context_impl(
29 attributes: proc_macro2::TokenStream,
30 item: proc_macro2::TokenStream,
31) -> proc_macro2::TokenStream {
32 let context_error_kind = unwrap_parse("attributes", syn::parse2::<TypePath>(attributes));
33 let mut item_fn = unwrap_parse("item", syn::parse2::<ItemFn>(item));
34 let (left, right) = if item_fn.sig.asyncness.is_some() {
35 (quote! {async move}, quote! {.await})
36 } else {
37 (quote! {move | |}, quote! {()})
38 };
39 let block = item_fn.block;
40 let body = parse_quote! {{
41 ::infinite_errors::ErrorContext::err_context(
42 (#left
43 #block
44 )#right,
45 #context_error_kind
46 )
47 }};
48 item_fn.block = Box::new(body);
49
50 item_fn.into_token_stream()
51}
52
53fn unwrap_parse<T>(name: &str, res: syn::parse::Result<T>) -> T {
54 match res {
55 Ok(x) => x,
56 Err(err) => panic!("failed to parse {name}: {err}"),
57 }
58}