1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{ parse_macro_input, FnArg, ItemFn, Pat };

#[proc_macro_attribute]
pub fn login_required(_: TokenStream, func: TokenStream) -> TokenStream {
    let func = parse_macro_input!(func as ItemFn);
    let func_vis = &func.vis;
    let func_block = &func.block;

    let login_ident = Ident::new("_id", Span::call_site());

    let func_sig = &func.sig;
    let func_name = &func_sig.ident;
    let func_generics = &func_sig.generics;
    let func_inputs = &func_sig.inputs;
    let func_output = &func_sig.output;
    let func_async = &func_sig.asyncness.unwrap();

    let identity_vec: Vec<_> = func_inputs
        .iter()
        .filter(|s| match s {
            FnArg::Typed(ref arg_type) => {
                if let Pat::Ident(ref id) = *arg_type.pat {
                    id.ident.eq(&login_ident)
                } else {
                    false
                }
            }
            _ => unreachable!("This not gonna happend!"),
        })
        .map(|s| match s {
            FnArg::Typed(ref arg) => &arg.pat,
            _ => unreachable!("This not gonna happend!"),
        })
        .collect();

    let identity = *identity_vec.get(0).unwrap();

    let expended = quote! {
        #func_vis #func_async fn #func_name #func_generics(#func_inputs) #func_output {
            if let Some(ident) = #identity.identity() {
                #func_block
            } else {
                actix_web::HttpResponse::Unauthorized().json("Unauthorized")
            }
        }
    };
    expended.into()
}