netdb_auth_macro_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, ItemFn, LitInt, LitStr, Token};
4use syn::parse::{Parse, ParseStream};
5
6struct ScopeArgs {
7    category: LitStr,
8    scope_code: Option<LitInt>,
9}
10
11impl Parse for ScopeArgs {
12    fn parse(input: ParseStream) -> syn::Result<Self> {
13        let category = input.parse()?;
14        let scope_code = if input.peek(Token![,]) {
15            input.parse::<Token![,]>()?;
16            Some(input.parse()?)
17        } else {
18            None
19        };
20
21        Ok(ScopeArgs { category, scope_code })
22    }
23}
24
25#[proc_macro_attribute]
26pub fn has_scope(attr: TokenStream, item: TokenStream) -> TokenStream {
27    let ScopeArgs { category, scope_code } = parse_macro_input!(attr as ScopeArgs);
28    let scope_formatted: Option<u32> = scope_code.map(|lit| lit.base10_parse().unwrap());
29
30    let category = category.value();
31    let input = parse_macro_input!(item as ItemFn);
32    let fn_name = &input.sig.ident;
33    let block = &input.block;
34    let inputs = &input.sig.inputs;
35    let output = &input.sig.output;
36    let attrs = &input.attrs;
37    let is_async = input.sig.asyncness.is_some();
38
39    let expanded = if scope_formatted.is_some() {
40        if is_async {
41            quote! {
42                #(#attrs)*
43                async fn #fn_name(#inputs) #output {
44                    let scope_check_successfull = user.has_scope(#category, Some(#scope_formatted));
45    
46                    #block
47                }
48            }
49        } else {
50            quote! {
51                #(#attrs)*
52                fn #fn_name(#inputs) #output {
53                    let scope_check_successfull = user.has_scope(#category, Some(#scope_formatted));
54    
55                    #block
56                }
57            }
58        }
59    } else {
60        if is_async {
61            quote! {
62                #(#attrs)*
63                async fn #fn_name(#inputs) #output {
64                    let scope_check_successfull = user.has_scope(#category, None);
65    
66                    #block
67                }
68            }
69        } else {
70            quote! {
71                #(#attrs)*
72                fn #fn_name(#inputs) #output {
73                    let scope_check_successfull = user.has_scope(#category, None);
74    
75                    #block
76                }
77            }
78        }
79    };
80
81    TokenStream::from(expanded)
82}