1use proc_macro::TokenStream;
2use syn::parse_macro_input;
3use syn::{Item, ItemImpl, LitStr};
4
5mod controller;
6mod decorators;
7mod dependency;
8mod events;
9mod file_upload;
10mod messaging;
11mod openapi;
12mod openapi_security;
13mod outside;
14mod protocol;
15mod schedule;
16mod util;
17mod validation;
18mod websocket;
19
20pub(crate) use util::{
21 expect_no_extractor_args, is_type_ident, option_inner_type, parse_optional_comma, push_error,
22 set_once,
23};
24
25use controller::expand_controller;
26use dependency::{expand_catch, expand_injectable, expand_module, CatchArgs, ModuleArgs};
27use events::expand_event_listener;
28use messaging::expand_message_controller;
29use outside::*;
30use schedule::expand_schedule;
31use websocket::{expand_websocket_gateway, WebSocketGatewayArgs};
32
33#[proc_macro_attribute]
34pub fn injectable(attr: TokenStream, item: TokenStream) -> TokenStream {
35 if !attr.is_empty() {
36 return syn::Error::new(
37 proc_macro2::TokenStream::from(attr)
38 .into_iter()
39 .next()
40 .unwrap()
41 .span(),
42 "#[injectable] does not accept arguments",
43 )
44 .to_compile_error()
45 .into();
46 }
47
48 let item = parse_macro_input!(item as Item);
49 match item {
50 Item::Struct(item_struct) => expand_injectable(item_struct)
51 .unwrap_or_else(syn::Error::into_compile_error)
52 .into(),
53 item => syn::Error::new_spanned(item, "#[injectable] can only be used on structs")
54 .to_compile_error()
55 .into(),
56 }
57}
58
59#[proc_macro_attribute]
60pub fn module(attr: TokenStream, item: TokenStream) -> TokenStream {
61 let args = parse_macro_input!(attr as ModuleArgs);
62 let item = parse_macro_input!(item as Item);
63
64 match item {
65 Item::Struct(item_struct) => expand_module(args, item_struct)
66 .unwrap_or_else(syn::Error::into_compile_error)
67 .into(),
68 item => syn::Error::new_spanned(item, "#[module] can only be used on structs")
69 .to_compile_error()
70 .into(),
71 }
72}
73
74#[proc_macro_attribute]
75pub fn catch(attr: TokenStream, item: TokenStream) -> TokenStream {
76 let args = parse_macro_input!(attr as CatchArgs);
77 let item = parse_macro_input!(item as Item);
78
79 match item {
80 Item::Struct(item_struct) => expand_catch(args, item_struct)
81 .unwrap_or_else(syn::Error::into_compile_error)
82 .into(),
83 item => syn::Error::new_spanned(item, "#[catch] can only be used on structs")
84 .to_compile_error()
85 .into(),
86 }
87}
88
89#[proc_macro_attribute]
90pub fn controller(attr: TokenStream, item: TokenStream) -> TokenStream {
91 let prefix = parse_macro_input!(attr as LitStr);
92 let item_impl = parse_macro_input!(item as ItemImpl);
93
94 expand_controller(prefix, item_impl)
95 .unwrap_or_else(syn::Error::into_compile_error)
96 .into()
97}
98
99#[proc_macro_attribute]
100pub fn websocket_gateway(attr: TokenStream, item: TokenStream) -> TokenStream {
101 let args = parse_macro_input!(attr as WebSocketGatewayArgs);
102 let item_impl = parse_macro_input!(item as ItemImpl);
103
104 expand_websocket_gateway(args, item_impl)
105 .unwrap_or_else(syn::Error::into_compile_error)
106 .into()
107}
108
109#[proc_macro_attribute]
110pub fn apply_decorators(_attr: TokenStream, item: TokenStream) -> TokenStream {
111 decorator_attribute_outside_controller("apply_decorators", item)
112}
113
114#[proc_macro_attribute]
115pub fn message_controller(attr: TokenStream, item: TokenStream) -> TokenStream {
116 if !attr.is_empty() {
117 return syn::Error::new(
118 proc_macro2::TokenStream::from(attr)
119 .into_iter()
120 .next()
121 .unwrap()
122 .span(),
123 "#[message_controller] does not accept arguments",
124 )
125 .to_compile_error()
126 .into();
127 }
128
129 let item_impl = parse_macro_input!(item as ItemImpl);
130 expand_message_controller(item_impl)
131 .unwrap_or_else(syn::Error::into_compile_error)
132 .into()
133}
134
135#[proc_macro_attribute]
136pub fn event_listener(attr: TokenStream, item: TokenStream) -> TokenStream {
137 if !attr.is_empty() {
138 return syn::Error::new(
139 proc_macro2::TokenStream::from(attr)
140 .into_iter()
141 .next()
142 .unwrap()
143 .span(),
144 "#[event_listener] does not accept arguments",
145 )
146 .to_compile_error()
147 .into();
148 }
149
150 let item_impl = parse_macro_input!(item as ItemImpl);
151 expand_event_listener(item_impl)
152 .unwrap_or_else(syn::Error::into_compile_error)
153 .into()
154}
155
156#[proc_macro_attribute]
157pub fn schedule(attr: TokenStream, item: TokenStream) -> TokenStream {
158 if !attr.is_empty() {
159 return syn::Error::new(
160 proc_macro2::TokenStream::from(attr)
161 .into_iter()
162 .next()
163 .unwrap()
164 .span(),
165 "#[schedule] does not accept arguments",
166 )
167 .to_compile_error()
168 .into();
169 }
170
171 let item_impl = parse_macro_input!(item as ItemImpl);
172 expand_schedule(item_impl)
173 .unwrap_or_else(syn::Error::into_compile_error)
174 .into()
175}
176
177#[proc_macro_attribute]
178pub fn subscribe_message(_attr: TokenStream, item: TokenStream) -> TokenStream {
179 websocket_attribute_outside_gateway("subscribe_message", item)
180}
181
182#[proc_macro_attribute]
183pub fn on_gateway_init(_attr: TokenStream, item: TokenStream) -> TokenStream {
184 websocket_attribute_outside_gateway("on_gateway_init", item)
185}
186
187#[proc_macro_attribute]
188pub fn on_gateway_connection(_attr: TokenStream, item: TokenStream) -> TokenStream {
189 websocket_attribute_outside_gateway("on_gateway_connection", item)
190}
191
192#[proc_macro_attribute]
193pub fn on_gateway_disconnect(_attr: TokenStream, item: TokenStream) -> TokenStream {
194 websocket_attribute_outside_gateway("on_gateway_disconnect", item)
195}
196
197#[proc_macro_attribute]
198pub fn cron(_attr: TokenStream, item: TokenStream) -> TokenStream {
199 schedule_attribute_outside_schedule("cron", item)
200}
201
202#[proc_macro_attribute]
203pub fn interval(_attr: TokenStream, item: TokenStream) -> TokenStream {
204 schedule_attribute_outside_schedule("interval", item)
205}
206
207#[proc_macro_attribute]
208pub fn timeout(_attr: TokenStream, item: TokenStream) -> TokenStream {
209 schedule_attribute_outside_schedule("timeout", item)
210}
211
212#[proc_macro_attribute]
213pub fn message_pattern(_attr: TokenStream, item: TokenStream) -> TokenStream {
214 message_attribute_outside_controller("message_pattern", item)
215}
216
217#[proc_macro_attribute]
218pub fn event_pattern(_attr: TokenStream, item: TokenStream) -> TokenStream {
219 message_attribute_outside_controller("event_pattern", item)
220}
221
222#[proc_macro_attribute]
223pub fn payload(_attr: TokenStream, item: TokenStream) -> TokenStream {
224 protocol_extractor_attribute_outside("payload", item)
225}
226
227#[proc_macro_attribute]
228pub fn message_body(_attr: TokenStream, item: TokenStream) -> TokenStream {
229 protocol_extractor_attribute_outside("message_body", item)
230}
231
232#[proc_macro_attribute]
233pub fn on_event(_attr: TokenStream, item: TokenStream) -> TokenStream {
234 event_attribute_outside_listener("on_event", item)
235}
236
237#[proc_macro_attribute]
238pub fn all(_attr: TokenStream, item: TokenStream) -> TokenStream {
239 route_attribute_outside_controller("all", item)
240}
241
242#[proc_macro_attribute]
243pub fn get(_attr: TokenStream, item: TokenStream) -> TokenStream {
244 route_attribute_outside_controller("get", item)
245}
246
247#[proc_macro_attribute]
248pub fn sse(_attr: TokenStream, item: TokenStream) -> TokenStream {
249 route_attribute_outside_controller("sse", item)
250}
251
252#[proc_macro_attribute]
253pub fn post(_attr: TokenStream, item: TokenStream) -> TokenStream {
254 route_attribute_outside_controller("post", item)
255}
256
257#[proc_macro_attribute]
258pub fn put(_attr: TokenStream, item: TokenStream) -> TokenStream {
259 route_attribute_outside_controller("put", item)
260}
261
262#[proc_macro_attribute]
263pub fn patch(_attr: TokenStream, item: TokenStream) -> TokenStream {
264 route_attribute_outside_controller("patch", item)
265}
266
267#[proc_macro_attribute]
268pub fn delete(_attr: TokenStream, item: TokenStream) -> TokenStream {
269 route_attribute_outside_controller("delete", item)
270}
271
272#[proc_macro_attribute]
273pub fn options(_attr: TokenStream, item: TokenStream) -> TokenStream {
274 route_attribute_outside_controller("options", item)
275}
276
277#[proc_macro_attribute]
278pub fn head(_attr: TokenStream, item: TokenStream) -> TokenStream {
279 route_attribute_outside_controller("head", item)
280}
281
282#[proc_macro_attribute]
283pub fn get_json(_attr: TokenStream, item: TokenStream) -> TokenStream {
284 route_attribute_outside_controller("get_json", item)
285}
286
287#[proc_macro_attribute]
288pub fn post_json(_attr: TokenStream, item: TokenStream) -> TokenStream {
289 route_attribute_outside_controller("post_json", item)
290}
291
292#[proc_macro_attribute]
293pub fn put_json(_attr: TokenStream, item: TokenStream) -> TokenStream {
294 route_attribute_outside_controller("put_json", item)
295}
296
297#[proc_macro_attribute]
298pub fn patch_json(_attr: TokenStream, item: TokenStream) -> TokenStream {
299 route_attribute_outside_controller("patch_json", item)
300}
301
302#[proc_macro_attribute]
303pub fn delete_json(_attr: TokenStream, item: TokenStream) -> TokenStream {
304 route_attribute_outside_controller("delete_json", item)
305}
306
307#[proc_macro_attribute]
308pub fn body(_attr: TokenStream, item: TokenStream) -> TokenStream {
309 extractor_attribute_outside_controller("body", item)
310}
311
312#[proc_macro_attribute]
313pub fn request(_attr: TokenStream, item: TokenStream) -> TokenStream {
314 extractor_attribute_outside_controller("request", item)
315}
316
317#[proc_macro_attribute]
318pub fn param(_attr: TokenStream, item: TokenStream) -> TokenStream {
319 extractor_attribute_outside_controller("param", item)
320}
321
322#[proc_macro_attribute]
323pub fn params(_attr: TokenStream, item: TokenStream) -> TokenStream {
324 extractor_attribute_outside_controller("params", item)
325}
326
327#[proc_macro_attribute]
328pub fn query(_attr: TokenStream, item: TokenStream) -> TokenStream {
329 extractor_attribute_outside_controller("query", item)
330}
331
332#[proc_macro_attribute]
333pub fn header(_attr: TokenStream, item: TokenStream) -> TokenStream {
334 extractor_attribute_outside_controller("header", item)
335}
336
337#[proc_macro_attribute]
338pub fn headers(_attr: TokenStream, item: TokenStream) -> TokenStream {
339 extractor_attribute_outside_controller("headers", item)
340}
341
342#[proc_macro_attribute]
343pub fn cookie(_attr: TokenStream, item: TokenStream) -> TokenStream {
344 extractor_attribute_outside_controller("cookie", item)
345}
346
347#[proc_macro_attribute]
348pub fn cookies(_attr: TokenStream, item: TokenStream) -> TokenStream {
349 extractor_attribute_outside_controller("cookies", item)
350}
351
352#[proc_macro_attribute]
353pub fn host_param(_attr: TokenStream, item: TokenStream) -> TokenStream {
354 extractor_attribute_outside_controller("host_param", item)
355}
356
357#[proc_macro_attribute]
358pub fn ip(_attr: TokenStream, item: TokenStream) -> TokenStream {
359 extractor_attribute_outside_controller("ip", item)
360}
361
362#[proc_macro_attribute]
363pub fn res(_attr: TokenStream, item: TokenStream) -> TokenStream {
364 extractor_attribute_outside_controller("res", item)
365}
366
367#[proc_macro_attribute]
368pub fn session(_attr: TokenStream, item: TokenStream) -> TokenStream {
369 extractor_attribute_outside_controller("session", item)
370}
371
372#[proc_macro_attribute]
373pub fn uploaded_file(_attr: TokenStream, item: TokenStream) -> TokenStream {
374 extractor_attribute_outside_controller("uploaded_file", item)
375}
376
377#[proc_macro_attribute]
378pub fn uploaded_files(_attr: TokenStream, item: TokenStream) -> TokenStream {
379 extractor_attribute_outside_controller("uploaded_files", item)
380}
381
382#[proc_macro_attribute]
383pub fn extract(_attr: TokenStream, item: TokenStream) -> TokenStream {
384 extractor_attribute_outside_controller("extract", item)
385}
386
387#[proc_macro_attribute]
388pub fn host(_attr: TokenStream, item: TokenStream) -> TokenStream {
389 host_attribute_outside_controller("host", item)
390}
391
392#[proc_macro_attribute]
393pub fn version(_attr: TokenStream, item: TokenStream) -> TokenStream {
394 version_attribute_outside_controller("version", item)
395}
396
397#[proc_macro_attribute]
398pub fn versions(_attr: TokenStream, item: TokenStream) -> TokenStream {
399 version_attribute_outside_controller("versions", item)
400}
401
402#[proc_macro_attribute]
403pub fn version_neutral(_attr: TokenStream, item: TokenStream) -> TokenStream {
404 version_attribute_outside_controller("version_neutral", item)
405}
406
407#[proc_macro_attribute]
408pub fn serialize(_attr: TokenStream, item: TokenStream) -> TokenStream {
409 serialization_attribute_outside_controller("serialize", item)
410}
411
412#[proc_macro_attribute]
413pub fn tag(_attr: TokenStream, item: TokenStream) -> TokenStream {
414 openapi_attribute_outside_controller("tag", item)
415}
416
417#[proc_macro_attribute]
418pub fn operation(_attr: TokenStream, item: TokenStream) -> TokenStream {
419 openapi_attribute_outside_controller("operation", item)
420}
421
422#[proc_macro_attribute]
423pub fn response(_attr: TokenStream, item: TokenStream) -> TokenStream {
424 openapi_attribute_outside_controller("response", item)
425}
426
427#[proc_macro_attribute]
428pub fn request_body(_attr: TokenStream, item: TokenStream) -> TokenStream {
429 openapi_attribute_outside_controller("request_body", item)
430}
431
432#[proc_macro_attribute]
433pub fn api_param(_attr: TokenStream, item: TokenStream) -> TokenStream {
434 openapi_attribute_outside_controller("api_param", item)
435}
436
437#[proc_macro_attribute]
438pub fn api_query(_attr: TokenStream, item: TokenStream) -> TokenStream {
439 openapi_attribute_outside_controller("api_query", item)
440}
441
442#[proc_macro_attribute]
443pub fn api_header(_attr: TokenStream, item: TokenStream) -> TokenStream {
444 openapi_attribute_outside_controller("api_header", item)
445}
446
447#[proc_macro_attribute]
448pub fn api_response_header(_attr: TokenStream, item: TokenStream) -> TokenStream {
449 openapi_attribute_outside_controller("api_response_header", item)
450}
451
452#[proc_macro_attribute]
453pub fn api_security(_attr: TokenStream, item: TokenStream) -> TokenStream {
454 openapi_attribute_outside_controller("api_security", item)
455}
456
457#[proc_macro_attribute]
458pub fn api_cookie_auth(_attr: TokenStream, item: TokenStream) -> TokenStream {
459 openapi_attribute_outside_controller("api_cookie_auth", item)
460}
461
462#[proc_macro_attribute]
463pub fn api_key_auth(_attr: TokenStream, item: TokenStream) -> TokenStream {
464 openapi_attribute_outside_controller("api_key_auth", item)
465}
466
467#[proc_macro_attribute]
468pub fn bearer_auth(_attr: TokenStream, item: TokenStream) -> TokenStream {
469 openapi_attribute_outside_controller("bearer_auth", item)
470}
471
472#[proc_macro_attribute]
473pub fn oauth2_auth(_attr: TokenStream, item: TokenStream) -> TokenStream {
474 openapi_attribute_outside_controller("oauth2_auth", item)
475}
476
477#[proc_macro_attribute]
478pub fn open_id_connect_auth(_attr: TokenStream, item: TokenStream) -> TokenStream {
479 openapi_attribute_outside_controller("open_id_connect_auth", item)
480}
481
482#[proc_macro_attribute]
483pub fn api_extra_model(_attr: TokenStream, item: TokenStream) -> TokenStream {
484 openapi_attribute_outside_controller("api_extra_model", item)
485}
486
487#[proc_macro_attribute]
488pub fn api_extension(_attr: TokenStream, item: TokenStream) -> TokenStream {
489 openapi_attribute_outside_controller("api_extension", item)
490}
491
492#[proc_macro_attribute]
493pub fn hide_from_openapi(_attr: TokenStream, item: TokenStream) -> TokenStream {
494 openapi_attribute_outside_controller("hide_from_openapi", item)
495}
496
497#[proc_macro_attribute]
498pub fn redirect(_attr: TokenStream, item: TokenStream) -> TokenStream {
499 response_attribute_outside_controller("redirect", item)
500}
501
502#[proc_macro_attribute]
503pub fn render(_attr: TokenStream, item: TokenStream) -> TokenStream {
504 render_attribute_outside_controller("render", item)
505}
506
507#[proc_macro_attribute]
508pub fn http_code(_attr: TokenStream, item: TokenStream) -> TokenStream {
509 http_code_attribute_outside_controller("http_code", item)
510}
511
512#[proc_macro_attribute]
513pub fn metadata(_attr: TokenStream, item: TokenStream) -> TokenStream {
514 metadata_attribute_outside_controller("metadata", item)
515}
516
517#[proc_macro_attribute]
518pub fn validate(_attr: TokenStream, item: TokenStream) -> TokenStream {
519 validation_attribute_outside_controller("validate", item)
520}
521
522#[proc_macro_attribute]
523pub fn skip_validation(_attr: TokenStream, item: TokenStream) -> TokenStream {
524 validation_attribute_outside_controller("skip_validation", item)
525}
526
527#[proc_macro_derive(ValidationSchema, attributes(serde))]
528pub fn derive_validation_schema(item: TokenStream) -> TokenStream {
529 let item_struct = parse_macro_input!(item as syn::ItemStruct);
530 validation::expand_validation_schema(item_struct)
531 .unwrap_or_else(syn::Error::into_compile_error)
532 .into()
533}
534
535#[proc_macro_attribute]
536pub fn use_guard(_attr: TokenStream, item: TokenStream) -> TokenStream {
537 pipeline_attribute_outside_controller("use_guard", item)
538}
539
540#[proc_macro_attribute]
541pub fn use_interceptor(_attr: TokenStream, item: TokenStream) -> TokenStream {
542 pipeline_attribute_outside_controller("use_interceptor", item)
543}
544
545#[proc_macro_attribute]
546pub fn use_filter(_attr: TokenStream, item: TokenStream) -> TokenStream {
547 pipeline_attribute_outside_controller("use_filter", item)
548}
549
550#[proc_macro_attribute]
551pub fn use_pipe(_attr: TokenStream, item: TokenStream) -> TokenStream {
552 pipeline_attribute_outside_controller("use_pipe", item)
553}
554
555#[proc_macro_attribute]
556pub fn cache_key(_attr: TokenStream, item: TokenStream) -> TokenStream {
557 cache_attribute_outside_controller("cache_key", item)
558}
559
560#[proc_macro_attribute]
561pub fn cache_ttl(_attr: TokenStream, item: TokenStream) -> TokenStream {
562 cache_attribute_outside_controller("cache_ttl", item)
563}