micro_timer_macros/
lib.rs1extern crate proc_macro;
10use proc_macro2::TokenStream;
11use quote::{quote, quote_spanned, ToTokens};
12use syn::spanned::Spanned;
13
14#[proc_macro_attribute]
30pub fn timed(
31 attrs: proc_macro::TokenStream,
32 item: proc_macro::TokenStream,
33) -> proc_macro::TokenStream {
34 inner_timed(attrs.into(), item.into()).into()
35}
36
37fn inner_timed(_attr_ts: TokenStream, fn_ts: TokenStream) -> TokenStream {
39 let ast = syn::parse2(fn_ts.clone()).unwrap();
40 let func = match parse_function(ast) {
41 Ok(f) => f,
42 Err(stream) => return stream,
43 };
44
45 let mut outer = func.clone();
46 let original_func_name = func.sig.ident.to_string();
47 let inner_block: TokenStream = func
48 .block
49 .stmts
50 .iter()
51 .map(|s| s.to_token_stream())
52 .collect();
53 let span = outer.sig.ident.span();
54
55 let block = quote_spanned! {
56 span=>
57 {
58 let __micro_timer_instant = ::std::time::Instant::now();
59 let __micro_timer_guard =
60 ::micro_timer::scopeguard::guard_on_success(
61 __micro_timer_instant,
62 |timer| {
63 if ::std::thread::panicking() {
64 return
65 }
66 crate::log::trace!(
67 "Duration of `{}`: {:?}",
68 #original_func_name,
69 timer.elapsed()
70 );
71 }
72 );
73
74 #inner_block
75 }
76 };
77
78 outer.block = syn::parse2(block).unwrap();
79
80 quote! {#outer}
81}
82
83fn parse_function(item: syn::Item) -> Result<syn::ItemFn, TokenStream> {
84 match item {
85 syn::Item::Fn(func) => {
86 if func.sig.asyncness.is_some() {
87 return Err(quote_spanned! {
88 func.span()=>
89 compile_error!("Cannot use `#[timed]` on async functions")
90 #func
91 });
92 }
93 Ok(func)
94 }
95 i => Err(quote_spanned! {
96 i.span()=>
97 compile_error!("`#[timed]` can only be used on functions");
98 #i
99 }),
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use pretty_assertions::assert_eq;
107
108 #[test]
109 fn test_output() {
110 let input = syn::parse_quote! {
111 fn my_super_function(_value: usize) -> usize {
112 let timer = 10;
113 timer
114 }
115 };
116
117 let expected: TokenStream = syn::parse_quote! {
118 fn my_super_function(_value: usize) -> usize {
119 let __micro_timer_instant = ::std::time::Instant::now();
120 let __micro_timer_guard =
121 ::micro_timer::scopeguard::guard_on_success(
122 __micro_timer_instant,
123 |timer| {
124 if ::std::thread::panicking() {
125 return
126 }
127 crate::log::trace!(
128 "Duration of `{}`: {:?}",
129 "my_super_function",
130 timer.elapsed()
131 );
132 }
133 );
134 let timer = 10;
135 timer
136 }
137 };
138 let output = inner_timed(TokenStream::new(), input);
139 assert_eq!(output.to_string(), expected.to_string());
140 }
141}