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
54
55
56
57
58
59
60
61
extern crate proc_macro;
//extern crate proc_macro2;
extern crate quote;
extern crate syn;
use core::convert::AsRef;
use proc_macro::TokenStream;

use quote::{format_ident, quote};
use syn::parse_macro_input;
use syn::AttributeArgs;
use syn::ItemFn;

#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
    let args = parse_macro_input!(attr as AttributeArgs);
    let mut path = None;
    let mut reqtype = None;
    for arg in args {
        match arg {
            syn::NestedMeta::Lit(syn::Lit::Str(ref fname)) => {
                let fname = quote!(#fname).to_string();
                path = Some(fname.as_str()[1..fname.len() - 1].to_owned());
            }
            syn::NestedMeta::Meta(syn::Meta::Path(ident)) => {
                let identstr = quote!(#ident).to_string();
                reqtype = Some(identstr);
            }
            _ => {
                println!("error");
            }
        }
    }
    let psitem = parse_macro_input!(item as ItemFn);
    let name = psitem.sig.ident.clone();
    let classname = syn::Ident::new(&format!("{}{}", "class_", name), psitem.sig.ident.span());
    let rtypestr = reqtype.expect("error");
    let callprefix = format_ident!("web");
    #[allow(unused_assignments)]
    let mut method = None;
    match rtypestr.as_ref() {
        "GET" => method = Some(format_ident!("get")),
        "POST" => method = Some(format_ident!("post")),
        "PUT" => method = Some(format_ident!("put")),
        "PATCH" => method = Some(format_ident!("patch")),
        "DELETE" => method = Some(format_ident!("delete")),
        "HEAD" => method = Some(format_ident!("head")),
        _ => method = Some(format_ident!("")),
    }
    let func = quote! {
        #[allow(non_camel_case_types)]
        pub struct #classname;
        #psitem
        inventory::submit!(Box::new(#classname) as Box<dyn ServiceFactory>);
        impl ServiceFactory for #classname {
        fn register(&self, config: &mut web::ServiceConfig) {
            config.route(#path, #callprefix::#method().to(#name));
        }
    }
        };
    func.into()
}