1extern crate proc_macro;
4use proc_macro::TokenStream;
5use quote::quote;
6use syn::{parse_macro_input, ItemFn, parse_quote, Block, Expr, Token, punctuated::Punctuated};
7use syn::parse::Parser;
8
9#[proc_macro_attribute]
32pub fn trace_with(attr: TokenStream, input: TokenStream) -> TokenStream {
33 let parser = Punctuated::<Expr, Token![,]>::parse_terminated;
34 let mut with_args: Vec<_> = parser.parse(attr).unwrap().into_iter().collect();
35 let with: Expr = with_args.remove(0);
36
37 let mut input = parse_macro_input!(input as ItemFn);
38 let fn_name = input.ident.clone();
39 let inner_block = input.block;
40 let retty = input.decl.output.clone();
41
42 let trace_wrapper: Block = parse_quote! {
43 {
44 use ::call_trace::Trace as _;
45 let __ctx = ::call_trace::CallContext {
46 file: file!(),
47 line: line!(),
48 fn_name: stringify!(#fn_name),
49 };
50
51 #with.on_pre(&__ctx);
52 let __r = {
53 let mut __f = || #retty #inner_block;
54 __f()
55 };
56 #with.on_post(&__ctx);
57
58 __r
59 }
60 };
61 input.block = Box::new(trace_wrapper);
62
63 TokenStream::from(quote! { #input })
64}