1extern crate proc_macro;
43
44mod route;
45
46use proc_macro::TokenStream;
47use quote::quote;
48use syn::parse_macro_input;
49
50#[proc_macro_attribute]
60pub fn web_get(args: TokenStream, input: TokenStream) -> TokenStream {
61 let args = parse_macro_input!(args as syn::AttributeArgs);
62 let gen_code = match route::Route::new(args, input, route::MethodType::Get) {
63 Ok(gen_code) => gen_code,
64 Err(err) => return err.to_compile_error().into(),
65 };
66 gen_code.generate()
67}
68
69#[proc_macro_attribute]
75pub fn web_post(args: TokenStream, input: TokenStream) -> TokenStream {
76 let args = parse_macro_input!(args as syn::AttributeArgs);
77 let gen_code = match route::Route::new(args, input, route::MethodType::Post) {
78 Ok(gen_code) => gen_code,
79 Err(err) => return err.to_compile_error().into(),
80 };
81 gen_code.generate()
82}
83
84#[proc_macro_attribute]
90pub fn web_put(args: TokenStream, input: TokenStream) -> TokenStream {
91 let args = parse_macro_input!(args as syn::AttributeArgs);
92 let gen_code = match route::Route::new(args, input, route::MethodType::Put) {
93 Ok(gen_code) => gen_code,
94 Err(err) => return err.to_compile_error().into(),
95 };
96 gen_code.generate()
97}
98
99#[proc_macro_attribute]
105pub fn web_delete(args: TokenStream, input: TokenStream) -> TokenStream {
106 let args = parse_macro_input!(args as syn::AttributeArgs);
107 let gen_code = match route::Route::new(args, input, route::MethodType::Delete) {
108 Ok(gen_code) => gen_code,
109 Err(err) => return err.to_compile_error().into(),
110 };
111 gen_code.generate()
112}
113
114#[proc_macro_attribute]
120pub fn web_head(args: TokenStream, input: TokenStream) -> TokenStream {
121 let args = parse_macro_input!(args as syn::AttributeArgs);
122 let gen_code = match route::Route::new(args, input, route::MethodType::Head) {
123 Ok(gen_code) => gen_code,
124 Err(err) => return err.to_compile_error().into(),
125 };
126 gen_code.generate()
127}
128
129#[proc_macro_attribute]
135pub fn web_connect(args: TokenStream, input: TokenStream) -> TokenStream {
136 let args = parse_macro_input!(args as syn::AttributeArgs);
137 let gen_code = match route::Route::new(args, input, route::MethodType::Connect) {
138 Ok(gen_code) => gen_code,
139 Err(err) => return err.to_compile_error().into(),
140 };
141 gen_code.generate()
142}
143
144#[proc_macro_attribute]
150pub fn web_options(args: TokenStream, input: TokenStream) -> TokenStream {
151 let args = parse_macro_input!(args as syn::AttributeArgs);
152 let gen_code = match route::Route::new(args, input, route::MethodType::Options) {
153 Ok(gen_code) => gen_code,
154 Err(err) => return err.to_compile_error().into(),
155 };
156 gen_code.generate()
157}
158
159#[proc_macro_attribute]
165pub fn web_trace(args: TokenStream, input: TokenStream) -> TokenStream {
166 let args = parse_macro_input!(args as syn::AttributeArgs);
167 let gen_code = match route::Route::new(args, input, route::MethodType::Trace) {
168 Ok(gen_code) => gen_code,
169 Err(err) => return err.to_compile_error().into(),
170 };
171 gen_code.generate()
172}
173
174#[proc_macro_attribute]
180pub fn web_patch(args: TokenStream, input: TokenStream) -> TokenStream {
181 let args = parse_macro_input!(args as syn::AttributeArgs);
182 let gen_code = match route::Route::new(args, input, route::MethodType::Patch) {
183 Ok(gen_code) => gen_code,
184 Err(err) => return err.to_compile_error().into(),
185 };
186 gen_code.generate()
187}
188
189#[proc_macro_attribute]
200pub fn rt_main(_: TokenStream, item: TokenStream) -> TokenStream {
201 let mut input = syn::parse_macro_input!(item as syn::ItemFn);
202 let attrs = &input.attrs;
203 let vis = &input.vis;
204 let sig = &mut input.sig;
205 let body = &input.block;
206 let name = &sig.ident;
207
208 if sig.asyncness.is_none() {
209 return syn::Error::new_spanned(sig.fn_token, "only async fn is supported")
210 .to_compile_error()
211 .into();
212 }
213
214 sig.asyncness = None;
215
216 (quote! {
217 #(#attrs)*
218 #vis #sig {
219 ntex::rt::System::new(stringify!(#name))
220 .block_on(async move { #body })
221 }
222 })
223 .into()
224}
225
226#[proc_macro_attribute]
237pub fn rt_test(_: TokenStream, item: TokenStream) -> TokenStream {
238 let input = syn::parse_macro_input!(item as syn::ItemFn);
239
240 let ret = &input.sig.output;
241 let name = &input.sig.ident;
242 let body = &input.block;
243 let attrs = &input.attrs;
244 let mut has_test_attr = false;
245
246 for attr in attrs {
247 if attr.path.is_ident("test") {
248 has_test_attr = true;
249 }
250 }
251
252 if input.sig.asyncness.is_none() {
253 return syn::Error::new_spanned(
254 input.sig.fn_token,
255 format!("only async fn is supported, {}", input.sig.ident),
256 )
257 .to_compile_error()
258 .into();
259 }
260
261 let result = if has_test_attr {
262 quote! {
263 #(#attrs)*
264 fn #name() #ret {
265 ntex::util::enable_test_logging();
266 ntex::rt::System::new("test")
267 .block_on(async { #body })
268 }
269 }
270 } else {
271 quote! {
272 #[test]
273 #(#attrs)*
274 fn #name() #ret {
275 ntex::util::enable_test_logging();
276 ntex::rt::System::new("test")
277 .block_on(async { #body })
278 }
279 }
280 };
281
282 result.into()
283}
284
285#[doc(hidden)]
296#[proc_macro_attribute]
297pub fn rt_test2(_: TokenStream, item: TokenStream) -> TokenStream {
298 let input = syn::parse_macro_input!(item as syn::ItemFn);
299
300 let ret = &input.sig.output;
301 let name = &input.sig.ident;
302 let body = &input.block;
303 let attrs = &input.attrs;
304 let mut has_test_attr = false;
305
306 for attr in attrs {
307 if attr.path.is_ident("test") {
308 has_test_attr = true;
309 }
310 }
311
312 if input.sig.asyncness.is_none() {
313 return syn::Error::new_spanned(
314 input.sig.fn_token,
315 format!("only async fn is supported, {}", input.sig.ident),
316 )
317 .to_compile_error()
318 .into();
319 }
320
321 let result = if has_test_attr {
322 quote! {
323 #(#attrs)*
324 fn #name() #ret {
325 ntex_rt::System::new("test")
326 .block_on(async { #body })
327 }
328 }
329 } else {
330 quote! {
331 #[test]
332 #(#attrs)*
333 fn #name() #ret {
334 ntex_rt::System::new("test")
335 .block_on(async { #body })
336 }
337 }
338 };
339
340 result.into()
341}
342
343#[doc(hidden)]
354#[proc_macro_attribute]
355pub fn rt_test_internal(_: TokenStream, item: TokenStream) -> TokenStream {
356 let input = syn::parse_macro_input!(item as syn::ItemFn);
357
358 let ret = &input.sig.output;
359 let name = &input.sig.ident;
360 let body = &input.block;
361 let attrs = &input.attrs;
362 let mut has_test_attr = false;
363
364 for attr in attrs {
365 if attr.path.is_ident("test") {
366 has_test_attr = true;
367 }
368 }
369
370 if input.sig.asyncness.is_none() {
371 return syn::Error::new_spanned(
372 input.sig.fn_token,
373 format!("only async fn is supported, {}", input.sig.ident),
374 )
375 .to_compile_error()
376 .into();
377 }
378
379 let result = if has_test_attr {
380 quote! {
381 #(#attrs)*
382 fn #name() #ret {
383 crate::util::enable_test_logging();
384 ntex_rt::System::new("test")
385 .block_on(async { #body })
386 }
387 }
388 } else {
389 quote! {
390 #[test]
391 #(#attrs)*
392 fn #name() #ret {
393 crate::util::enable_test_logging();
394 ntex_rt::System::new("test")
395 .block_on(async { #body })
396 }
397 }
398 };
399
400 result.into()
401}