1use std::ops::Deref;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::spanned::Spanned;
6
7#[proc_macro_attribute]
8pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
9 let item_fn: syn::ItemFn = syn::parse(item).unwrap();
10 let value: syn::LitStr = syn::parse(attr).unwrap();
11
12 let sig = item_fn.sig;
13 let name = sig.ident.clone();
14 let body = item_fn.block.deref();
15 let return_type = sig.output;
16
17 let fn_args = sig.inputs;
18 let is_body_args = !fn_args.is_empty();
19 let mut path = value.value();
22 let new_wildcard = if path.contains("/:") {
39 let path_clone = path.clone();
40 let mut iter = path_clone.split(':');
41 path = iter.next().unwrap().to_string();
42 let id = iter.next().unwrap().to_string();
43 if path.len() != 1 {
44 path.pop();
45 };
46 quote! {get_route = get_route.set_wildcard(#id.into());}
47 } else {
48 quote! {}
49 };
50
51 let span = return_type.span();
52 let return_error = match return_type {
53 syn::ReturnType::Default => Some(
54 syn::Error::new(span, "You're forgetting to return something...").into_compile_error(),
55 ),
56 _ => None,
57 };
58
59 if let Some(e) = return_error {
60 return e.into();
61 }
62
63 let new_get_body = if is_body_args {
77 let mut fn_args_iter = fn_args.iter();
78 let first_arg_name = fn_args_iter.next().unwrap();
79 let arg_type = match first_arg_name {
80 syn::FnArg::Typed(i) => i.to_owned(),
81 _ => todo!(),
82 };
83
84 quote! {
85 let mut get_route = GetRouteWithReqAndRes::new()
86 .set_path(#path.into());
87
88 fn body<'b>(try_from_req: &'b mut Request, _sock: &'b mut std::net::TcpStream) -> Response {
89 let #arg_type = try_from_req.into();
90 #body.into()
91 }
92
93 get_route = get_route.set_body(body);
99 }
100 } else {
101 quote! {
102 let mut get_route = BasicGetRoute::new()
103 .set_path(#path.into());
104
105 fn body() -> Response {
106 #body.into()
107 }
108
109 get_route = get_route.set_body(body);
110 }
111 };
112
113 let output = quote! {
114 fn #name() -> Box<dyn Route> {
115 #new_get_body
122 #new_wildcard
123
124 Box::new(get_route)
125 }
126 };
127
128 output.into()
129}
130
131#[proc_macro_attribute]
132pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
133 let item: syn::ItemFn = syn::parse(item).unwrap();
135 let value: syn::LitStr = syn::parse(attr).unwrap();
136
137 let fn_args = item.sig.inputs;
138 let name = item.sig.ident.clone();
139 let body = item.block.deref();
140 let return_type = item.sig.output;
141
142 let is_body_args = !fn_args.is_empty();
143
144 let mut path = value.value();
145 let new_wildcard = if path.contains("/:") {
146 let path_clone = path.clone();
147 let mut iter = path_clone.split(':');
148 path = iter.next().unwrap().to_string();
149 let id = iter.next().unwrap().to_string();
150 if path.len() != 1 {
151 path.pop();
152 };
153 quote! {post_route = post_route.set_wildcard(#id.into());}
154 } else {
155 quote! {}
156 };
157
158 let return_error = match return_type {
159 syn::ReturnType::Default => Some(
160 syn::Error::new(
161 return_type.span(),
162 "You're forgetting to return something...",
163 )
164 .into_compile_error(),
165 ),
166 _ => None,
167 };
168
169 if let Some(e) = return_error {
170 return e.into();
171 }
172
173 let new_post_body = if is_body_args {
174 let first_arg_name = fn_args.first().unwrap();
175 let arg_type = match first_arg_name {
176 syn::FnArg::Typed(i) => i.to_owned(),
177 _ => todo!(),
178 };
179 quote! {
191
192 let mut post_route = PostRouteWithReqAndRes::new()
193 .set_path(#path.into());
194
195 fn body<'b>(try_from_req: &'b mut Request, _sock: &'b mut std::net::TcpStream) -> Response {
196 let #arg_type = try_from_req.into();
197 #body.into()
198 }
199
200 post_route = post_route.set_body(body);
201 }
202 } else {
203 quote! {
204 let mut post_route = BasicPostRoute::new()
205 .set_path(#path.into());
206
207 fn body() -> Response {
208 #body.into()
209 }
210
211 post_route = post_route.set_body(body);
212 }
213 };
214
215 let output = quote! {
216 fn #name() -> Box<dyn Route> {
217 #new_post_body
223 #new_wildcard
224
225 Box::new(post_route)
226 }
227 };
228
229 output.into()
240}