| 1 | extern crate proc_macro; |
| 2 | use proc_macro::TokenStream; |
| 3 | use quote::{quote, ToTokens}; |
| 4 | use syn::{parse_macro_input, parse_quote, ImplItem, ItemFn, ItemImpl}; |
| 5 | |
| 6 | #[proc_macro_attribute ] |
| 7 | pub fn function ( |
| 8 | _attr: TokenStream, |
| 9 | item: TokenStream, |
| 10 | ) -> TokenStream { |
| 11 | let mut function: ItemFn = parse_macro_input!(item as ItemFn); |
| 12 | let instrumented_function_name: String = function.sig.ident.to_string(); |
| 13 | |
| 14 | let body: &Box = &function.block; |
| 15 | let new_body: syn::Block = impl_block(body, &instrumented_function_name); |
| 16 | |
| 17 | function.block = Box::new(new_body); |
| 18 | |
| 19 | (quote! { |
| 20 | #function |
| 21 | }) |
| 22 | .into() |
| 23 | } |
| 24 | |
| 25 | #[proc_macro_attribute ] |
| 26 | pub fn skip ( |
| 27 | _attr: TokenStream, |
| 28 | item: TokenStream, |
| 29 | ) -> TokenStream { |
| 30 | item |
| 31 | } |
| 32 | |
| 33 | #[proc_macro_attribute ] |
| 34 | pub fn all_functions ( |
| 35 | _attr: TokenStream, |
| 36 | item: TokenStream, |
| 37 | ) -> TokenStream { |
| 38 | let mut content = parse_macro_input!(item as ItemImpl); |
| 39 | let struct_name = content.self_ty.to_token_stream().to_string(); |
| 40 | |
| 41 | 'func_loop: for block in &mut content.items { |
| 42 | // Currently, we only care about the function impl part. |
| 43 | // In the future, expand the code to following if we are interested in other parts |
| 44 | // |
| 45 | // match block { |
| 46 | // ImplItem::Fn(ref mut func) => { |
| 47 | // for func_attr in &func.attrs { |
| 48 | // if let syn::Meta::Path(ref func_attr_info) = func_attr.meta { |
| 49 | // let attr_seg = func_attr_info.segments.last().unwrap(); |
| 50 | // if attr_seg.ident.to_string() == "skip".to_string() { |
| 51 | // continue 'func_loop; |
| 52 | // } |
| 53 | // } |
| 54 | // } |
| 55 | // let prev_block = &func.block; |
| 56 | // let func_name = func.sig.ident.to_string(); |
| 57 | // func.block = impl_block(prev_block, &func_name); |
| 58 | // } |
| 59 | // ImplItem::Macro(_) => { // some code... }, |
| 60 | // ImplItem::Type(_) => { // some code... }, |
| 61 | // _ => {} |
| 62 | // } |
| 63 | let ImplItem::Fn(ref mut func) = block else { |
| 64 | continue; |
| 65 | }; |
| 66 | |
| 67 | for func_attr in &func.attrs { |
| 68 | let func_attr_info = func_attr.path(); |
| 69 | if func_attr_info.segments.is_empty() { |
| 70 | continue; |
| 71 | } |
| 72 | if func_attr_info.segments.first().unwrap().ident != "profiling" { |
| 73 | continue; |
| 74 | } |
| 75 | if func_attr_info.segments.last().unwrap().ident == "skip" { |
| 76 | continue 'func_loop; |
| 77 | } |
| 78 | } |
| 79 | let prev_block = &func.block; |
| 80 | let calling_info = format!(" {}: {}" , struct_name, func.sig.ident); |
| 81 | func.block = impl_block(prev_block, &calling_info); |
| 82 | } |
| 83 | |
| 84 | (quote!( |
| 85 | #content |
| 86 | )) |
| 87 | .into() |
| 88 | } |
| 89 | |
| 90 | #[cfg (not(any( |
| 91 | feature = "profile-with-puffin" , |
| 92 | feature = "profile-with-optick" , |
| 93 | feature = "profile-with-superluminal" , |
| 94 | feature = "profile-with-tracing" , |
| 95 | feature = "profile-with-tracy" |
| 96 | )))] |
| 97 | fn impl_block( |
| 98 | body: &syn::Block, |
| 99 | _instrumented_function_name: &str, |
| 100 | ) -> syn::Block { |
| 101 | parse_quote! { |
| 102 | { |
| 103 | #body |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | #[cfg (any( |
| 109 | feature = "profile-with-puffin" , |
| 110 | feature = "profile-with-optick" , |
| 111 | feature = "profile-with-superluminal" , |
| 112 | feature = "profile-with-tracy" |
| 113 | ))] |
| 114 | fn impl_block( |
| 115 | body: &syn::Block, |
| 116 | _instrumented_function_name: &str, |
| 117 | ) -> syn::Block { |
| 118 | parse_quote! { |
| 119 | { |
| 120 | profiling::function_scope!(); |
| 121 | |
| 122 | #body |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | #[cfg (feature = "profile-with-tracing" )] |
| 128 | fn impl_block( |
| 129 | body: &syn::Block, |
| 130 | instrumented_function_name: &str, |
| 131 | ) -> syn::Block { |
| 132 | parse_quote! { |
| 133 | { |
| 134 | let _fn_span = profiling::tracing::span!(profiling::tracing::Level::INFO, #instrumented_function_name); |
| 135 | let _fn_span_entered = _fn_span.enter(); |
| 136 | |
| 137 | #body |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | |