1mod include_addr;
2
3use core::panic;
4use proc_macro::TokenStream;
5use proc_macro2::Ident;
6use std::fmt::Debug;
7use syn::__private::quote::quote;
8use syn::__private::ToTokens;
9use syn::{FnArg, ItemFn, Lit, Pat, PatType, Type, TypePath, TypeReference};
10
11#[derive(Debug)]
12enum ArgType {
13 TypePath(TypePath),
14 TypeRef(TypeReference),
15}
16
17impl ToTokens for ArgType {
18 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
19 match self {
20 ArgType::TypePath(ty) => ty.to_tokens(tokens),
21 ArgType::TypeRef(ty) => ty.to_tokens(tokens),
22 }
23 }
24}
25
26type FnItems = (
27 ItemFn,
28 Ident,
29 String,
30 Vec<Ident>,
31 Vec<ArgType>,
32 Vec<Ident>,
33 Vec<ArgType>,
34 Vec<Ident>,
35 Vec<ArgType>,
36 Vec<Ident>,
37 Vec<ArgType>,
38 Vec<Ident>,
39 Vec<ArgType>,
40);
41
42fn get_fn_and_args_from_stream(attr: TokenStream, item: TokenStream) -> FnItems {
43 let item = syn::parse::<ItemFn>(item.clone()).unwrap();
44 let attr = syn::parse::<Lit>(attr).unwrap();
45 let mut path = String::new();
46 if let Lit::Str(lit) = attr {
47 path = lit.value()
48 } else {
49 panic!("Path should be string")
50 }
51 let ident = item.clone().sig.ident;
52 let args = item.clone().sig.inputs.into_iter().collect::<Vec<FnArg>>();
53 let mut args_ident = vec![];
54 let mut args_ty = vec![];
55 let mut args_ident_state = vec![];
56 let mut args_ident_json = vec![];
57 let mut args_ty_json = vec![];
58 let mut args_ty_state = vec![];
59 let mut args_ident_session = vec![];
60 let mut args_ty_session = vec![];
61 let mut args_ident_cookie = vec![];
62 let mut args_ty_cookie = vec![];
63
64 for arg in &args {
65 if let FnArg::Typed(PatType { pat, ty, .. }) = arg {
66 if let Pat::Ident(ident) = *pat.clone() {
67 args_ident.push(ident.ident.clone());
68 }
69 if let Type::Path(ty) = *ty.clone() {
70 let seg = ty.path.segments.iter().next().unwrap().clone().ident;
71 if &seg.to_string() == "State" {
72 args_ty_state.push(ArgType::TypePath(ty.clone()));
73 if let Pat::Ident(ident) = *pat.clone() {
74 args_ident_state.push(ident.ident.clone());
75 }
76 } else if &seg.to_string() == "CookieSession" {
77 args_ty_session.push(ArgType::TypePath(ty.clone()));
78 if let Pat::Ident(ident) = *pat.clone() {
79 args_ident_session.push(ident.ident.clone());
80 }
81 } else if &seg.to_string() == "CookieJar" {
82 args_ty_cookie.push(ArgType::TypePath(ty.clone()));
83 if let Pat::Ident(ident) = *pat.clone() {
84 args_ident_cookie.push(ident.ident.clone());
85 }
86 } else {
87 args_ty_json.push(ArgType::TypePath(ty.clone()));
88 if let Pat::Ident(ident) = *pat.clone() {
89 args_ident_json.push(ident.ident.clone());
90 }
91 }
92 args_ty.push(ArgType::TypePath(ty))
93 }
94 }
95 }
96 (
97 item,
98 ident,
99 path,
100 args_ident,
101 args_ty,
102 args_ident_json,
103 args_ty_json,
104 args_ident_state,
105 args_ty_state,
106 args_ident_session,
107 args_ty_session,
108 args_ident_cookie,
109 args_ty_cookie,
110 )
111}
112
113fn get_stream(method: &str, fn_items: FnItems) -> TokenStream {
114 let (
115 item,
116 ident,
117 path,
118 args_ident,
119 _args_ty,
120 args_ident_json,
121 args_ty_json,
122 args_ident_state,
123 args_ty_state,
124 args_ident_session,
125 args_ty_session,
126 args_ident_cookie,
127 args_ty_cookie,
128 ) = fn_items;
129
130 let vis = item.vis.clone();
131
132 let method = match method {
133 "get" => quote! { Method::GET },
134 "post" => quote! {Method::POST},
135 "put" => quote! {Method::PUT},
136 "delete" => quote! {Method::DELETE},
137 _ => panic!("Unhanding method"),
138 };
139 let stream = quote! {
140
141 #vis fn #ident() -> Route {
142 use std::future::Future;
143 use std::pin::Pin;
144 use nutt_web::http::method::Method;
145 use nutt_web::http::request::Request;
146 use nutt_web::modules::session::Session;
147 use nutt_web::http::cookie::CookieJar;
148 let f = |req: Request| -> Pin<Box<dyn Future<Output = Response> + Send + Sync>> {
149 #item
150 #(
151 let #args_ident_json: #args_ty_json = if let Ok(value) = req.body_json() {
152 value
153 } else { panic!("Args parsing error") };
154 )*
155 #(
156 let #args_ident_state: #args_ty_state = if let Some(value) = req.get_state().get(stringify!(#args_ident_state)) {
157 if let Some(value) = value.downcast_ref::<#args_ty_state>() {
158 value.clone()
159 } else {panic!("Downcast state type error")}
160 } else { panic!("Args parsing error") };
161 )*
162 #(
163 let #args_ident_session: #args_ty_session = {
164 if req.get_session().is_some() {
165 match req.get_session().as_ref() {
166 Some(Session::Cookie(session)) => {session.clone()}
167 None => {panic!("")}
168 }
169 } else { panic!("Args parsing error") }
170 };
171 )*
172 #(
173 let #args_ident_cookie: #args_ty_cookie = {
174 req.get_cookie_jar()
175 };
176 )*
177 Box::pin(#ident(#(#args_ident.clone(),)*))
178 } as fn(Request) -> _;
179
180 return Route::new(#method, #path, f)
181 }
182 };
183
184 stream.into()
185}
186
187#[proc_macro_attribute]
188pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
189 let fn_items = get_fn_and_args_from_stream(attr, item);
190 get_stream("get", fn_items)
191}
192
193#[proc_macro_attribute]
194pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
195 let fn_items = get_fn_and_args_from_stream(attr, item);
196 get_stream("post", fn_items)
197}
198
199#[proc_macro_attribute]
200pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream {
201 let fn_items = get_fn_and_args_from_stream(attr, item);
202 get_stream("put", fn_items)
203}
204
205#[proc_macro_attribute]
206pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
207 let fn_items = get_fn_and_args_from_stream(attr, item);
208 get_stream("delete", fn_items)
209}
210
211#[proc_macro]
212pub fn include_addr(_input: TokenStream) -> TokenStream {
213 include_addr::include_addr(_input)
214}