1extern crate proc_macro;
2extern crate proc_macro2;
3extern crate quote;
4extern crate syn;
5
6use core::convert::AsRef;
7use proc_macro::TokenStream;
8
9use proc_macro2::Span;
10use quote::{format_ident, quote};
11use syn::parse_macro_input;
12use syn::AttributeArgs;
13use syn::ItemFn;
14use syn::{ImplItem, ItemImpl};
15#[proc_macro_attribute]
20pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
21 let args = parse_macro_input!(attr as AttributeArgs);
22 let mut path = None;
23 let mut reqtype = None;
24 for arg in args {
25 match arg {
26 syn::NestedMeta::Lit(syn::Lit::Str(ref fname)) => {
27 let fname = quote!(#fname).to_string();
28 path = Some(fname.as_str()[1..fname.len() - 1].to_owned());
29 }
30 syn::NestedMeta::Meta(syn::Meta::Path(ident)) => {
31 let identstr = quote!(#ident).to_string();
32 reqtype = Some(identstr);
33 }
34 _ => {
35 println!("error");
36 }
37 }
38 }
39 let psitem = parse_macro_input!(item as ItemFn);
40 let name = psitem.sig.ident.clone();
41 let classname = syn::Ident::new(&format!("{}{}", "class_", name), psitem.sig.ident.span());
42 let rtypestr = reqtype.expect("error");
43 let callprefix = format_ident!("web");
44 #[allow(unused_assignments)]
45 let mut method = None;
46 match rtypestr.as_ref() {
47 "GET" => method = Some(format_ident!("get")),
48 "POST" => method = Some(format_ident!("post")),
49 "PUT" => method = Some(format_ident!("put")),
50 "PATCH" => method = Some(format_ident!("patch")),
51 "DELETE" => method = Some(format_ident!("delete")),
52 "HEAD" => method = Some(format_ident!("head")),
53 _ => method = Some(format_ident!("")),
54 }
55 let func = quote! {
56 #[allow(non_camel_case_types)]
57 pub struct #classname;
58 #psitem
59 inventory::submit!(Box::new(#classname) as Box<dyn ServiceFactory>);
60 impl ServiceFactory for #classname {
61 fn register(&self, config: &mut web::ServiceConfig) {
62 config.route(#path, #callprefix::#method().to(#name));
63 }
64 }
65 };
66 func.into()
67}
68#[proc_macro_attribute]
84pub fn route_res(attr: TokenStream, item: TokenStream) -> TokenStream {
85 let mut itimpl = parse_macro_input!(item as ItemImpl);
87 let args = parse_macro_input!(attr as AttributeArgs);
88 let mut path = None;
89 let mut reqtype = None;
90 for arg in args {
91 match arg {
92 syn::NestedMeta::Lit(syn::Lit::Str(ref fname)) => {
93 let fname = quote!(#fname).to_string();
94 path = Some(fname.as_str()[1..fname.len() - 1].to_owned());
95 }
96 syn::NestedMeta::Meta(syn::Meta::Path(ident)) => {
97 let identstr = quote!(#ident).to_string();
98 reqtype = Some(identstr);
99 }
100 _ => {
101 println!("error");
102 }
103 }
104 }
105 let self_ty = &itimpl.self_ty;
106 let mut nameident = quote! {#self_ty};
107 let classname = syn::Ident::new(&format!("{}{}", "class_", nameident), Span::call_site());
109 let callprefix = format_ident!("web");
111 let method = format_ident!("get");
112 let mut methods = vec![];
113 for arg in itimpl.items.iter() {
114 match arg {
116 ImplItem::Method(m) => {
117 methods.push(m.sig.ident.to_string())
119 }
120 ImplItem::Type(t) => {
121 println!("ImplItem::Type {:?}", t.ident.to_string());
122 }
123 ImplItem::Const(t) => {
124 println!("ImplItem::Type {:?}", t.ident.to_string());
125 }
126 _ => {}
127 }
128 }
129 let mut methodscode = vec![];
131 for method in methods{
132 let methodident = format_ident!("{}",method.to_string());
133 let regcode = quote!{
134 config.route(#path, #callprefix::#methodident().to(#nameident::#methodident));
135 };
136 methodscode.push(regcode);
137 }
138
139 let mut func = quote! {
140 pub struct #classname;
141 #itimpl
151 inventory::submit!(Box::new(#classname) as Box<dyn ServiceFactory>);
152 impl ServiceFactory for #classname {
154 fn register(&self, config: &mut web::ServiceConfig) {
155 #(#methodscode)*
156 }
158 }
159 };
160 func.into()
162}