netdb_auth_macro_derive/
lib.rs1use 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}