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
#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate darling;
extern crate proc_macro;
use darling::FromMeta;

#[derive(Debug, FromMeta)]
struct MacroArgs {
    #[darling(default)]
    print: Option<String>,
    #[darling(default)]
    prefix: Option<String>,
    #[darling(default)]
    suffix: Option<String>,
}

#[proc_macro_attribute]
pub fn exec_time(
    metadata: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let attr_args = parse_macro_input!(metadata as syn::AttributeArgs);
    let args: MacroArgs = match MacroArgs::from_list(&attr_args) {
        Ok(v) => v,
        Err(e) => {
            return e.write_errors().into();
        }
    };

    let print_arg = args.print.unwrap_or("always".to_string());

    if print_arg.eq(&"always".to_string())
        || (print_arg.eq(&"debug".to_string()) && cfg!(debug_assertions))
    {
        let input_fn: syn::ItemFn = parse_macro_input!(input as syn::ItemFn);
        let visibility = input_fn.vis;
        let ident = input_fn.ident;
        let inputs = input_fn.decl.inputs;
        let output = input_fn.decl.output;
        let generics = &input_fn.decl.generics;
        let where_clause = &input_fn.decl.generics.where_clause;
        let block = input_fn.block;
        let mut print_str = "".to_string();
        if let Some(pre) = args.prefix {
            print_str.push_str(&format!("{}::", pre));
        }
        print_str.push_str(&ident.to_string());
        if let Some(suffix) = args.suffix {
            print_str.push_str(&format!("::{}", suffix));
        }

        (quote!(
            #visibility fn #ident #generics (#inputs) #output #where_clause {
                let start_time = std::time::Instant::now();
                let f = || { #block };
                let r = f();
                println!("Time {}: {} mills", #print_str, (std::time::Instant::now() - start_time).as_millis());
                r
            }
        ))
        .into()
    } else {
        proc_macro::TokenStream::from(input).into()
    }
}