async_log_attributes/
lib.rs

1//! Proc Macro attributes for the `async-log` crate.
2
3#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)]
4#![deny(missing_debug_implementations, nonstandard_style)]
5#![recursion_limit = "512"]
6
7extern crate proc_macro;
8
9use proc_macro::TokenStream;
10use quote::quote;
11
12/// Defines the async main function.
13///
14/// # Examples
15///
16/// ```ignore
17/// #[span]
18/// async fn main() -> std::io::Result<()> {
19///     Ok(())
20/// }
21/// ```
22#[proc_macro_attribute]
23pub fn instrument(_attr: TokenStream, item: TokenStream) -> TokenStream {
24    let input = syn::parse_macro_input!(item as syn::ItemFn);
25
26    let attrs = &input.attrs;
27    let vis = &input.vis;
28    let constness = &input.constness;
29    let unsafety = &input.unsafety;
30    let asyncness = &input.asyncness;
31    let abi = &input.abi;
32
33    let generics = &input.decl.generics;
34    let name = &input.ident;
35    let inputs = &input.decl.inputs;
36    let output = &input.decl.output;
37    let body = &input.block.stmts;
38
39    let args: Vec<syn::Pat> = inputs
40        .pairs()
41        .filter_map(|pair| match pair.into_value() {
42            syn::FnArg::Captured(arg) => Some(arg.pat.clone()),
43            _ => return None,
44        })
45        .collect();
46
47    let names: String = args
48        .iter()
49        .enumerate()
50        .map(|(i, _arg)| {
51            let mut string = format!(", arg_{}", i);
52            string.push_str("={}");
53            string
54        })
55        .collect();
56
57    let result = quote! {
58        #(#attrs)*
59        #vis #constness #unsafety #asyncness #abi fn #generics #name(#(#inputs)*) #output {
60            let __name = format!("{}#{}", file!(), stringify!(#name));
61            let __args = format!("{}{}", __name, format_args!(#names, #(#args)*));
62            async_log::span!(__args, {
63                #(#body)*
64            })
65        }
66    };
67
68    result.into()
69}