sword_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::parse_macro_input;
4
5mod config;
6mod shared;
7
8mod controller {
9    pub mod expand;
10    pub mod generation;
11    pub mod parsing;
12
13    pub mod routes {
14        mod expand;
15        mod generation;
16        mod parsing;
17
18        pub use expand::*;
19        pub use generation::*;
20        pub use parsing::*;
21    }
22
23    pub use expand::expand_controller;
24    pub use routes::expand_controller_routes;
25}
26
27mod middlewares;
28
29mod injectable;
30
31/// Defines a handler for HTTP GET requests.
32/// This macro should be used inside an `impl` block of a struct annotated with the `#[controller]` macro.
33///
34/// ### Parameters
35/// - `path`: The path for the GET request, e.g., `"/items"`
36///
37/// ### Usage
38/// ```rust,ignore
39/// #[controller("/api")]
40/// struct MyController {}
41///
42/// #[routes]
43/// impl MyController {
44///     #[get("/items")]
45///     async fn get_items(&self) -> HttpResponse {
46///         HttpResponse::Ok().message("List of items")
47///     }
48/// }
49/// ```
50#[proc_macro_attribute]
51pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
52    let _ = attr;
53    item
54}
55
56/// Defines a handler for HTTP POST requests.
57/// This macro should be used inside an `impl` block of a struct annotated with the `#[controller]` macro.
58///
59/// ### Parameters
60/// - `path`: The path for the POST request, e.g., `"/api"`
61///
62/// ## Usage
63/// ```rust,ignore
64/// #[controller("/api")]
65/// struct MyController {}
66///
67/// #[routes]
68/// impl MyController {
69///     #[post("/items")]
70///     async fn create_item(&self, req: Request) -> HttpResult<HttpResponse> {
71///         Ok(HttpResponse::Ok().message("Item created"))
72///     }
73/// }
74/// ```
75#[proc_macro_attribute]
76pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
77    let _ = attr;
78    item
79}
80
81/// Defines a handler for HTTP PUT requests.
82/// This macro should be used inside an `impl` block of a struct annotated with the `#[controller]` macro.
83///
84/// ### Parameters
85/// - `path`: The path for the PUT request, e.g., `"/items"`
86///
87/// ## Usage
88/// ```rust,ignore
89/// #[controller("/api")]
90/// struct MyController {}
91///
92/// #[routes]
93/// impl MyController {
94///     #[put("/item/{id}")]
95///     async fn update_item(&self, req: Request) -> HttpResult<HttpResponse> {
96///         Ok(HttpResponse::Ok().message("Item updated"))
97///     }
98/// }
99/// ```
100#[proc_macro_attribute]
101pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream {
102    let _ = attr;
103    item
104}
105
106/// Defines a handler for HTTP DELETE requests.
107/// This macro should be used inside an `impl` block of a struct annotated with the `#[controller]` macro.
108///
109/// ### Parameters
110/// - `path`: The path for the DELETE request, e.g., `"/item/{id}"`
111///
112/// ## Usage
113/// ```rust,ignore
114/// #[controller("/api")]
115/// struct MyController {}
116///
117/// #[routes]
118/// impl MyController {
119///     #[delete("/item/{id}")]
120///     async fn delete_item(&self, req: Request) -> HttpResult<HttpResponse> {
121///         Ok(HttpResponse::Ok().message("Item deleted"))
122///     }
123/// }
124/// ```
125#[proc_macro_attribute]
126pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
127    let _ = attr;
128    item
129}
130
131/// Defines a handler for PATCH DELETE requests.
132/// This macro should be used inside an `impl` block of a struct annotated with the `#[controller]` macro.
133///
134/// ### Parameters
135/// - `path`: The path for the PATCH request, e.g., `"/item/{id}"`
136///
137/// ## Usage
138/// ```rust,ignore
139/// #[controller("/api")]
140/// struct MyController {}
141///
142/// #[routes]
143/// impl MyController {
144///     #[patch("/item/{id}")]
145///     async fn patch_item(&self, req: Request) -> HttpResult<HttpResponse> {
146///         Ok(HttpResponse::Ok().message("Item patched"))
147///     }
148/// }
149/// ```
150#[proc_macro_attribute]
151pub fn patch(attr: TokenStream, item: TokenStream) -> TokenStream {
152    let _ = attr;
153    item
154}
155
156/// Defines a controller with a base path.
157/// This macro should be used in combination with the `#[routes]` macro.
158///
159/// ### Parameters
160/// - `base_path`: The base path for the controller, e.g., "/api
161///
162/// ### Usage
163/// ```rust,ignore
164/// #[controller("/base_path")]
165/// struct MyController {}
166///
167/// #[routes]
168/// impl MyController {
169///     #[get("/sub_path")]
170///     async fn my_handler(&self) -> HttpResponse {
171///        Ok(HttpResponse::Ok().message("Hello from MyController"))    
172///     }
173/// }
174/// ```
175#[proc_macro_attribute]
176pub fn controller(attr: TokenStream, item: TokenStream) -> TokenStream {
177    controller::expand_controller(attr, item)
178        .unwrap_or_else(|err| err.to_compile_error().into())
179}
180
181/// Implements the routes for a controller defined with the `#[controller]` macro.
182///
183/// ### Usage
184/// ```rust,ignore
185/// #[controller("/base_path")]
186/// struct MyController {}
187///
188/// #[routes]
189/// impl MyController {
190///     #[get("/sub_path")]
191///     async fn my_handler(&self) -> HttpResponse {
192///        HttpResponse::Ok().message("Hello from MyController")
193///     }
194/// }
195/// ```
196#[proc_macro_attribute]
197pub fn routes(attr: TokenStream, item: TokenStream) -> TokenStream {
198    controller::expand_controller_routes(attr, item)
199        .unwrap_or_else(|err| err.to_compile_error().into())
200}
201
202///  Declares a middleware struct.
203#[proc_macro_attribute]
204pub fn middleware(attr: TokenStream, item: TokenStream) -> TokenStream {
205    middlewares::expand_middleware(attr, item)
206        .unwrap_or_else(|err| err.to_compile_error().into())
207}
208
209/// Declares a executable middleware to apply to a route controller.
210/// This macro should be used inside an `impl` block of a struct annotated with the `#[controller]` macro.
211///
212/// ### Parameters
213/// - `MiddlewareName`: The name of the middleware struct that implements the `Middleware` or `MiddlewareWithConfig` trait.
214///   Also can receive an instance of a `tower-http` service layer like `CorsLayer`, `CompressionLayer`, `TraceLayer`, etc.
215///   If the layer can be added without errors on `Application::with_layer` there will not be any problem using it.  
216///
217/// - `config`: (Optional) Configuration parameters for the middleware,
218///
219/// ### Handle errors
220/// To throw an error from a middleware, simply return an `Err` with an `HttpResponse`
221/// struct in the same way as a controller handler.
222///
223/// ### Usage
224/// ```rust,ignore
225/// pub struct RoleMiddleware;
226///
227/// impl MiddlewareWithConfig<Vec<&str>> for RoleMiddleware {
228///     async fn handle(roles: Vec<&str>, req: Request, next: Next) -> MiddlewareResult {
229///         next!(ctx, next)
230///     }
231/// }
232///
233/// #[controller("/api")]
234/// struct MyController {}
235///
236/// #[routes]
237/// impl MyController {
238///     #[get("/items")]
239///     #[uses(RoleMiddleware)]
240///     async fn get_items(&self) -> HttpResponse {
241///         HttpResponse::Ok().message("List of items")
242///     }
243/// }
244/// ```
245#[proc_macro_attribute]
246pub fn uses(attr: TokenStream, item: TokenStream) -> TokenStream {
247    let _ = attr;
248    item
249}
250
251/// Defines a configuration struct for the application.
252/// This macro generates the necessary code to deserialize the struct from
253/// the configuration toml file.
254///
255/// The struct must derive `Deserialize` from `serde`.
256///
257/// ### Parameters
258/// - `key`: The key in the configuration file where the struct is located.
259///
260/// ### Usage
261/// ```rust,ignore
262/// #[derive(Deserialize)]
263/// #[config(key = "my-section")]
264/// struct MyConfig {
265///     my_key: String,
266/// }
267/// ```
268///
269/// This allows you to access the configuration in your handlers or middlewares
270///
271/// ```rust,ignore
272/// #[controller("/some_path")]
273/// struct SomeController {
274///     my_config: MyConfig,
275/// }
276///
277/// #[routes]
278/// impl SomeController {
279///     #[get("/config")]
280///     async fn get_config(&self) -> HttpResponse {
281///         let message = format!("Config key: {}", &self.config.my_key);
282///
283///         HttpResponse::Ok().message(message)
284///     }
285/// }
286#[proc_macro_attribute]
287pub fn config(attr: TokenStream, item: TokenStream) -> TokenStream {
288    config::expand_config_struct(attr, item)
289}
290
291/// Marks a struct as injectable.
292///
293/// This macro generates the necessary code to register the struct
294/// in the dependency injection container. It can be used with or without
295/// parameters.
296///
297/// ### Parameters
298///
299/// - `kind`: (Optional) Specifies the kind of injectable.
300///   It can be either `provider` or `component`.
301///
302///  `provider`: The struct that has to be instantiated manually and
303///   registered in the container. The struct will be treated as a singleton by default.
304///
305///  `component`: The struct will be instantiated automatically by the container
306///   based on its dependencies. It's also treated as a singleton by default.
307///
308///   By default, if no kind is provided, it will be treated as `component`.
309///
310/// - `no_derive_clone`: (Optional) If provided, the struct will not derive the `Clone` automatically.
311///   By default, the struct will derive `Clone` if all its fields implement `Clone`.
312///
313/// ### Usage of `#[injectable]` without parameters
314///
315/// ```rust,ignore
316/// #[injectable]
317/// pub struct TaskRepository {
318///     db: Database,
319/// }
320///
321/// impl TaskRepository {
322///     pub async fn create(&self, task: Value) {
323///         self.db.insert("tasks", task).await;
324///     }
325///
326///     pub async fn find_all(&self) -> Option<Vec<Value>> {
327///         self.db.get_all("tasks").await
328///     }
329/// }
330/// ```
331///
332/// ### Usage of `#[injectable(instance)]` with parameters
333///
334/// ```rust,ignore
335/// #[injectable(kind = "provider")]
336/// pub struct Database {
337///     db: Store,
338/// }
339///
340/// impl Database {
341///     pub async fn new(db_conf: DatabaseConfig) -> Self {
342///         let db = Arc::new(RwLock::new(HashMap::new()));
343///
344///         db.write().await.insert(db_conf.collection_name, Vec::new());
345///
346///         Self { db }
347///     }
348///
349///     pub async fn insert(&self, table: &'static str, record: Value) {
350///         let mut db = self.db.write().await;
351///
352///         if let Some(table_data) = db.get_mut(table) {
353///             table_data.push(record);
354///         }
355///     }
356///
357///     pub async fn get_all(&self, table: &'static str) -> Option<Vec<Value>> {
358///         let db = self.db.read().await;
359///
360///         db.get(table).cloned()
361///     }
362/// }
363/// ```
364#[proc_macro_attribute]
365pub fn injectable(attr: TokenStream, item: TokenStream) -> TokenStream {
366    injectable::expand_injectable(attr, item)
367        .unwrap_or_else(|err| err.to_compile_error().into())
368}
369
370/// ### This is just a re-export of `tokio::main` to simplify the initial setup of
371/// ### Sword, you can use your own version of tokio adding it to your
372/// ### `Cargo.toml`, we are providing this initial base by default
373///
374/// ---
375///
376/// Marks async function to be executed by the selected runtime. This macro
377/// helps set up a `Runtime` without requiring the user to use
378/// [Runtime](../tokio/runtime/struct.Runtime.html) or
379/// [Builder](../tokio/runtime/struct.Builder.html) directly.
380///
381/// Note: This macro is designed to be simplistic and targets applications that
382/// do not require a complex setup. If the provided functionality is not
383/// sufficient, you may be interested in using
384/// [Builder](../tokio/runtime/struct.Builder.html), which provides a more
385/// powerful interface.
386///
387/// Note: This macro can be used on any function and not just the `main`
388/// function. Using it on a non-main function makes the function behave as if it
389/// was synchronous by starting a new runtime each time it is called. If the
390/// function is called often, it is preferable to create the runtime using the
391/// runtime builder so the runtime can be reused across calls.
392///
393/// # Non-worker async function
394///
395/// Note that the async function marked with this macro does not run as a
396/// worker. The expectation is that other tasks are spawned by the function here.
397/// Awaiting on other futures from the function provided here will not
398/// perform as fast as those spawned as workers.
399///
400/// # Multi-threaded runtime
401///
402/// To use the multi-threaded runtime, the macro can be configured using
403///
404/// ```rust,ignore
405/// #[tokio::main(flavor = "multi_thread", worker_threads = 10)]
406/// # async fn main() {}
407/// ```
408///
409/// The `worker_threads` option configures the number of worker threads, and
410/// defaults to the number of cpus on the system. This is the default flavor.
411///
412/// Note: The multi-threaded runtime requires the `rt-multi-thread` feature
413/// flag.
414///
415/// # Current thread runtime
416///
417/// To use the single-threaded runtime known as the `current_thread` runtime,
418/// the macro can be configured using
419///
420/// ```rust,ignore
421/// #[tokio::main(flavor = "current_thread")]
422/// # async fn main() {}
423/// ```
424///
425/// ## Function arguments:
426///
427/// Arguments are allowed for any functions aside from `main` which is special
428///
429/// ## Usage
430///
431/// ### Using the multi-thread runtime
432///
433/// ```ignore
434/// #[tokio::main]
435/// async fn main() {
436///     println!("Hello world");
437/// }
438/// ```
439///
440/// Equivalent code not using `#[tokio::main]`
441///
442/// ```ignore
443/// fn main() {
444///     tokio::runtime::Builder::new_multi_thread()
445///         .enable_all()
446///         .build()
447///         .unwrap()
448///         .block_on(async {
449///             println!("Hello world");
450///         })
451/// }
452/// ```
453///
454/// ### Using current thread runtime
455///
456/// The basic scheduler is single-threaded.
457///
458/// ```ignore
459/// #[tokio::main(flavor = "current_thread")]
460/// async fn main() {
461///     println!("Hello world");
462/// }
463/// ```
464///
465/// Equivalent code not using `#[tokio::main]`
466///
467/// ```ignore
468/// fn main() {
469///     tokio::runtime::Builder::new_current_thread()
470///         .enable_all()
471///         .build()
472///         .unwrap()
473///         .block_on(async {
474///             println!("Hello world");
475///         })
476/// }
477/// ```
478///
479/// ### Set number of worker threads
480///
481/// ```ignore
482/// #[tokio::main(worker_threads = 2)]
483/// async fn main() {
484///     println!("Hello world");
485/// }
486/// ```
487///
488/// Equivalent code not using `#[tokio::main]`
489///
490/// ```ignore
491/// fn main() {
492///     tokio::runtime::Builder::new_multi_thread()
493///         .worker_threads(2)
494///         .enable_all()
495///         .build()
496///         .unwrap()
497///         .block_on(async {
498///             println!("Hello world");
499///         })
500/// }
501/// ```
502///
503/// ### Configure the runtime to start with time paused
504///
505/// ```ignore
506/// #[tokio::main(flavor = "current_thread", start_paused = true)]
507/// async fn main() {
508///     println!("Hello world");
509/// }
510/// ```
511///
512/// Equivalent code not using `#[tokio::main]`
513///
514/// ```ignore
515/// fn main() {
516///     tokio::runtime::Builder::new_current_thread()
517///         .enable_all()
518///         .start_paused(true)
519///         .build()
520///         .unwrap()
521///         .block_on(async {
522///             println!("Hello world");
523///         })
524/// }
525/// ```
526///
527/// Note that `start_paused` requires the `test-util` feature to be enabled.
528///
529/// ### Rename package
530///
531/// ```ignore
532/// use tokio as tokio1;
533///
534/// #[tokio1::main(crate = "tokio1")]
535/// async fn main() {
536///     println!("Hello world");
537/// }
538/// ```
539///
540/// Equivalent code not using `#[tokio::main]`
541///
542/// ```ignore
543/// use tokio as tokio1;
544///
545/// fn main() {
546///     tokio1::runtime::Builder::new_multi_thread()
547///         .enable_all()
548///         .build()
549///         .unwrap()
550///         .block_on(async {
551///             println!("Hello world");
552///         })
553/// }
554/// ```
555///
556/// ### Configure unhandled panic behavior
557///
558/// Available options are `shutdown_runtime` and `ignore`. For more details, see
559/// [`Builder::unhandled_panic`].
560///
561/// This option is only compatible with the `current_thread` runtime.
562///
563/// ```no_run, ignore
564/// # #![allow(unknown_lints, unexpected_cfgs)]
565/// #[cfg(tokio_unstable)]
566/// #[tokio::main(flavor = "current_thread", unhandled_panic = "shutdown_runtime")]
567/// async fn main() {
568///     let _ = tokio::spawn(async {
569///         panic!("This panic will shutdown the runtime.");
570///     }).await;
571/// }
572/// # #[cfg(not(tokio_unstable))]
573/// # fn main() { }
574/// ```
575///
576/// Equivalent code not using `#[tokio::main]`
577///
578/// ```no_run, ignore
579/// # #![allow(unknown_lints, unexpected_cfgs)]
580/// #[cfg(tokio_unstable)]
581/// fn main() {
582///     tokio::runtime::Builder::new_current_thread()
583///         .enable_all()
584///         .unhandled_panic(UnhandledPanic::ShutdownRuntime)
585///         .build()
586///         .unwrap()
587///         .block_on(async {
588///             let _ = tokio::spawn(async {
589///                 panic!("This panic will shutdown the runtime.");
590///             }).await;
591///         })
592/// }
593/// # #[cfg(not(tokio_unstable))]
594/// # fn main() { }
595/// ```
596///
597/// **Note**: This option depends on Tokio's [unstable API][unstable]. See [the
598/// documentation on unstable features][unstable] for details on how to enable
599/// Tokio's unstable features.
600///
601/// [`Builder::unhandled_panic`]: ../tokio/runtime/struct.Builder.html#method.unhandled_panic
602/// [unstable]: ../tokio/index.html#unstable-features
603#[proc_macro_attribute]
604pub fn main(_args: TokenStream, item: TokenStream) -> TokenStream {
605    let input = parse_macro_input!(item as syn::ItemFn);
606
607    let fn_body = input.block.clone();
608    let fn_attrs = input.attrs.clone();
609    let fn_vis = input.vis.clone();
610    let _fn_sig = input.sig;
611
612    #[allow(unused)]
613    let mut output = quote! {};
614
615    if cfg!(feature = "hot-reload") {
616        output = quote! {
617
618            async fn __internal_main() {
619                #fn_body
620            }
621
622            #(#fn_attrs)*
623            #fn_vis fn main() {
624                ::sword::__internal::tokio_runtime::Builder::new_multi_thread()
625                    .enable_all()
626                    .build()
627                    .expect("Failed building the Runtime")
628                    .block_on(::sword::__internal::dioxus_devtools::serve_subsecond(__internal_main))
629            }
630        };
631    } else {
632        output = quote! {
633            #(#fn_attrs)*
634            #fn_vis fn main() {
635                ::sword::__internal::tokio_runtime::Builder::new_multi_thread()
636                    .enable_all()
637                    .build()
638                    .expect("Failed building the Runtime")
639                    .block_on( async #fn_body )
640            }
641        };
642    }
643
644    output.into()
645}