captains_log_helper/
lib.rs1#![recursion_limit = "128"]
2
3
4extern crate proc_macro;
5extern crate syn;
6use proc_macro2::TokenStream;
7use quote::{quote, ToTokens};
8use syn::{
9 parse_macro_input, spanned::Spanned, token, AttributeArgs, Expr, ExprBlock, ExprClosure,
10 ItemFn, Result, ReturnType,
11};
12
13struct FormattedAttributes {
14 begin_expr: TokenStream,
15 end_expr: TokenStream,
16}
17
18impl FormattedAttributes {
19 fn get_streams(name: String) -> Self {
20 let fmt_begin = format!("+++ {} begin +++", name);
21 let fmt_end = format!("--- {} end ---", name);
22 let begin_expr = quote! {log::info!(#fmt_begin); };
23 let end_expr = quote! {log::info!(#fmt_end); };
24 FormattedAttributes { begin_expr, end_expr }
25 }
26}
27
28fn make_closure(original: &ItemFn) -> ExprClosure {
29 let body = Box::new(Expr::Block(ExprBlock {
30 attrs: Default::default(),
31 label: Default::default(),
32 block: *original.block.clone(),
33 }));
34
35 ExprClosure {
36 attrs: Default::default(),
37 asyncness: Default::default(),
38 movability: Default::default(),
39 capture: Some(token::Move { span: original.span() }),
40 or1_token: Default::default(),
41 inputs: Default::default(),
42 or2_token: Default::default(),
43 output: ReturnType::Default,
44 body,
45 }
46}
47
48fn replace_function_headers(original: ItemFn, new: &mut ItemFn) {
49 let block = new.block.clone();
50 *new = original;
51 new.block = block;
52}
53
54fn generate_function(closure: &ExprClosure, expressions: FormattedAttributes) -> Result<ItemFn> {
55 let FormattedAttributes { begin_expr, end_expr } = expressions;
56 let code = quote! {
57 fn temp() {
58 #begin_expr;
59 let _ = (#closure)();
60 #end_expr;
61 }
62 };
63
64 syn::parse2(code)
65}
66
67#[proc_macro_attribute]
93pub fn logfn(
94 attr: proc_macro::TokenStream, item: proc_macro::TokenStream,
95) -> proc_macro::TokenStream {
96 let _attr = parse_macro_input!(attr as AttributeArgs);
97 let original_fn: ItemFn = parse_macro_input!(item as ItemFn);
98 let parsed_attributes = FormattedAttributes::get_streams(original_fn.sig.ident.to_string());
99 let closure = make_closure(&original_fn);
100 let mut new_fn =
101 generate_function(&closure, parsed_attributes).expect("Failed Generating Function");
102 replace_function_headers(original_fn, &mut new_fn);
103 new_fn.into_token_stream().into()
104}