1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use proc_macro::TokenStream;
use quote::quote;
use syn::fold::Fold;
use syn::parse::{Parse, ParseStream};
use syn::{parse_macro_input, Block, Expr, ExprBlock, ItemFn, LitStr, Stmt};
struct MetricName {
name: LitStr,
}
impl Parse for MetricName {
fn parse(input: ParseStream) -> syn::Result<Self> {
let name: LitStr = input.parse()?;
Ok(Self { name })
}
}
impl Fold for MetricName {
fn fold_item_fn(&mut self, i: ItemFn) -> ItemFn {
let block = *i.block;
let name = i.sig.ident.to_string();
let mut statements: Vec<Stmt> = Vec::with_capacity(2);
let metric_name = self.name.value();
let macro_stmt = quote!(
let _guard = function_timer::FunctionTimer::new(#metric_name.to_string(), #name.to_string());
);
let macro_stmt: Stmt = syn::parse2(macro_stmt).unwrap();
statements.push(macro_stmt);
statements.push(Stmt::Expr(Expr::Block(ExprBlock {
attrs: vec![],
label: None,
block,
})));
let new_block = Block {
brace_token: Default::default(),
stmts: statements,
};
ItemFn {
attrs: i.attrs,
vis: i.vis,
sig: i.sig,
block: Box::new(new_block),
}
}
}
enum ImplOrFn {
Function(ItemFn),
}
impl Parse for ImplOrFn {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(Self::Function(input.parse()?))
}
}
#[proc_macro_attribute]
pub fn time(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut args = parse_macro_input!(attr as MetricName);
let input = parse_macro_input!(item as ImplOrFn);
match input {
ImplOrFn::Function(item_fn) => {
let output = args.fold_item_fn(item_fn);
TokenStream::from(quote!(#output))
}
}
}