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