1use proc_macro::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{parse_macro_input, punctuated::Punctuated, ItemFn, Meta, Token};
4
5#[allow(clippy::doc_overindented_list_items)]
22#[proc_macro_attribute]
23pub fn cvlr_hook_on_entry(attr: TokenStream, input: TokenStream) -> TokenStream {
24 let attr = parse_macro_input!(attr with Punctuated::<Meta, Token![,]>::parse_terminated);
26
27 if attr.len() != 1 {
28 return quote! {
29 compile_error!("Expected 1 argument");
30 }
31 .into();
32 }
33
34 let arg = attr.first().unwrap();
35
36 let mut fn_item = parse_macro_input!(input as ItemFn);
38
39 let tokens_start: syn::Stmt = syn::parse_quote! { #arg; };
41
42 fn_item.block.stmts.insert(0, tokens_start);
43
44 fn_item.into_token_stream().into()
45}
46
47#[allow(clippy::doc_overindented_list_items)]
67#[proc_macro_attribute]
68pub fn cvlr_hook_on_exit(attr: TokenStream, input: TokenStream) -> TokenStream {
69 let attr = parse_macro_input!(attr with Punctuated::<Meta, Token![,]>::parse_terminated);
72 if attr.len() != 1 {
73 return quote! {
74 compile_error!("Expected 1 argument");
75 }
76 .into();
77 }
78
79 let arg = &attr.first().unwrap();
80
81 let mut fn_item = parse_macro_input!(input as ItemFn);
83 let ret_type = &fn_item.sig.output;
84
85 let stmt_end: syn::Stmt = syn::parse_quote! { #arg; };
87
88 let len = fn_item.block.stmts.len();
90
91 match ret_type {
92 syn::ReturnType::Default => {
93 fn_item.block.stmts.insert(len, stmt_end);
95 }
96 syn::ReturnType::Type(_, _) => {
97 fn_item.block.stmts.insert(len - 1, stmt_end);
99 }
100 }
101
102 fn_item.into_token_stream().into()
103}