tracing_orchestra_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3
4#[proc_macro_derive(Orchestra)]
5pub fn derive_orchestra(tokens: TokenStream) -> TokenStream {
6    let struct_ast = syn::parse_macro_input!(tokens as syn::ItemStruct);
7    let struct_attrs = struct_ast.attrs;
8    let struct_vis = struct_ast.vis;
9    let struct_name = struct_ast.ident;
10    let struct_generics = struct_ast.generics.params;
11    let struct_where = struct_ast.generics.where_clause;
12
13    let ret = quote!(
14        #(#struct_attrs)*
15        #struct_vis impl<#struct_generics> tracing_orchestra::Orchestra for #struct_name<#struct_generics> #struct_where {}
16    );
17    eprintln!("{}", ret.to_string());
18    ret.into()
19}
20
21#[proc_macro_attribute]
22pub fn orchestra(attrs: TokenStream, implementation: TokenStream) -> TokenStream {
23    let implementation_ast = syn::parse_macro_input!(implementation as syn::ItemImpl);
24    let on_attrs: proc_macro2::TokenStream = attrs.into();
25    let impl_attrs = implementation_ast.attrs;
26    let impl_defaultness = implementation_ast.defaultness;
27    let impl_unsafety = implementation_ast.unsafety;
28    let impl_generics = implementation_ast.generics.params;
29    let impl_trait = if let Some(t) = implementation_ast.trait_ {
30        if let Some(_) = t.0 {
31            let p = t.1;
32            quote!(! #p for)
33        } else {
34            let p = t.1;
35            if p.segments.is_empty() {
36                quote!()
37            } else {
38                quote!(#p for)
39            }
40        }
41    } else {
42        TokenStream::new().into()
43    };
44    let impl_type = implementation_ast.self_ty;
45    let impl_items = implementation_ast.items.into_iter().map(|item| match item {
46        syn::ImplItem::Fn(impl_fn) => {
47            let attrs = impl_fn
48                .attrs
49                .iter()
50                .filter(|attr| {
51                    attr.path()
52                        .segments
53                        .last()
54                        .map(|x| x.ident == "instrument")
55                        .unwrap_or(false)
56                })
57                .collect::<Vec<_>>();
58            if attrs.is_empty() {
59                quote!(
60                    #[tracing::instrument(#on_attrs)]
61                    #impl_fn
62                )
63            } else {
64                let attrs_others = impl_fn
65                    .attrs
66                    .iter()
67                    .filter(|attr2| {
68                        attr2
69                            .path()
70                            .segments
71                            .iter()
72                            .last()
73                            .map(|x| x.ident != "instrument")
74                            .unwrap_or(false)
75                    })
76                    .collect::<Vec<_>>();
77                let vis = impl_fn.vis;
78                let defaultness = impl_fn.defaultness;
79                let sig = impl_fn.sig;
80                let block = impl_fn.block;
81                quote!(
82                    #(#attrs)*
83                    #(#attrs_others)*
84                    #vis #defaultness #sig #block
85                )
86            }
87        }
88        _ => {
89            eprintln!("support only fn");
90            quote!(#item)
91        }
92    });
93    let ret = quote!(
94        #(#impl_attrs)*
95        #impl_defaultness #impl_unsafety impl #impl_generics #impl_trait #impl_type {
96            #(#impl_items)*
97        }
98    );
99
100    eprintln!("{}", ret.to_string());
101    ret.into()
102}