sword_macros/
lib.rs

1mod config;
2mod controller;
3mod utils;
4
5use crate::controller::implementation;
6use proc_macro::TokenStream;
7use quote::quote;
8use syn::{parse_macro_input, parse_quote};
9
10#[proc_macro_attribute]
11pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
12    let _ = attr;
13    item
14}
15
16#[proc_macro_attribute]
17pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
18    let _ = attr;
19    item
20}
21
22#[proc_macro_attribute]
23pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream {
24    let _ = attr;
25    item
26}
27
28#[proc_macro_attribute]
29pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
30    let _ = attr;
31    item
32}
33
34#[proc_macro_attribute]
35pub fn patch(attr: TokenStream, item: TokenStream) -> TokenStream {
36    let _ = attr;
37    item
38}
39
40#[proc_macro_attribute]
41pub fn controller(attr: TokenStream, item: TokenStream) -> TokenStream {
42    controller::expand_controller(attr, item)
43}
44
45#[deprecated(since = "0.1.5", note = "Use `#[routes]` instead")]
46#[proc_macro_attribute]
47pub fn controller_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
48    implementation::expand_controller_impl(attr, item)
49}
50
51#[proc_macro_attribute]
52pub fn routes(attr: TokenStream, item: TokenStream) -> TokenStream {
53    implementation::expand_controller_impl(attr, item)
54}
55
56#[proc_macro_attribute]
57pub fn middleware(attr: TokenStream, item: TokenStream) -> TokenStream {
58    let _ = attr;
59    item
60}
61
62#[proc_macro_attribute]
63pub fn config(attr: TokenStream, item: TokenStream) -> TokenStream {
64    config::expand_config_struct(attr, item)
65}
66
67/// ### This is just a re-export of `tokio::main` to simplify the initial setup of
68/// ### Sword, you can use your own version of tokio adding it to your
69/// ### `Cargo.toml`, we are providing this initial base by default
70///
71/// ---
72///
73/// Marks async function to be executed by the selected runtime. This macro
74/// helps set up a `Runtime` without requiring the user to use
75/// [Runtime](../tokio/runtime/struct.Runtime.html) or
76/// [Builder](../tokio/runtime/struct.Builder.html) directly.
77///
78/// Note: This macro is designed to be simplistic and targets applications that
79/// do not require a complex setup. If the provided functionality is not
80/// sufficient, you may be interested in using
81/// [Builder](../tokio/runtime/struct.Builder.html), which provides a more
82/// powerful interface.
83///
84/// Note: This macro can be used on any function and not just the `main`
85/// function. Using it on a non-main function makes the function behave as if it
86/// was synchronous by starting a new runtime each time it is called. If the
87/// function is called often, it is preferable to create the runtime using the
88/// runtime builder so the runtime can be reused across calls.
89///
90/// # Non-worker async function
91///
92/// Note that the async function marked with this macro does not run as a
93/// worker. The expectation is that other tasks are spawned by the function here.
94/// Awaiting on other futures from the function provided here will not
95/// perform as fast as those spawned as workers.
96///
97/// # Multi-threaded runtime
98///
99/// To use the multi-threaded runtime, the macro can be configured using
100///
101/// ```rust,ignore
102/// #[tokio::main(flavor = "multi_thread", worker_threads = 10)]
103/// # async fn main() {}
104/// ```
105///
106/// The `worker_threads` option configures the number of worker threads, and
107/// defaults to the number of cpus on the system. This is the default flavor.
108///
109/// Note: The multi-threaded runtime requires the `rt-multi-thread` feature
110/// flag.
111///
112/// # Current thread runtime
113///
114/// To use the single-threaded runtime known as the `current_thread` runtime,
115/// the macro can be configured using
116///
117/// ```rust,ignore
118/// #[tokio::main(flavor = "current_thread")]
119/// # async fn main() {}
120/// ```
121///
122/// ## Function arguments:
123///
124/// Arguments are allowed for any functions aside from `main` which is special
125///
126/// ## Usage
127///
128/// ### Using the multi-thread runtime
129///
130/// ```ignore
131/// #[tokio::main]
132/// async fn main() {
133///     println!("Hello world");
134/// }
135/// ```
136///
137/// Equivalent code not using `#[tokio::main]`
138///
139/// ```ignore
140/// fn main() {
141///     tokio::runtime::Builder::new_multi_thread()
142///         .enable_all()
143///         .build()
144///         .unwrap()
145///         .block_on(async {
146///             println!("Hello world");
147///         })
148/// }
149/// ```
150///
151/// ### Using current thread runtime
152///
153/// The basic scheduler is single-threaded.
154///
155/// ```ignore
156/// #[tokio::main(flavor = "current_thread")]
157/// async fn main() {
158///     println!("Hello world");
159/// }
160/// ```
161///
162/// Equivalent code not using `#[tokio::main]`
163///
164/// ```ignore
165/// fn main() {
166///     tokio::runtime::Builder::new_current_thread()
167///         .enable_all()
168///         .build()
169///         .unwrap()
170///         .block_on(async {
171///             println!("Hello world");
172///         })
173/// }
174/// ```
175///
176/// ### Set number of worker threads
177///
178/// ```ignore
179/// #[tokio::main(worker_threads = 2)]
180/// async fn main() {
181///     println!("Hello world");
182/// }
183/// ```
184///
185/// Equivalent code not using `#[tokio::main]`
186///
187/// ```ignore
188/// fn main() {
189///     tokio::runtime::Builder::new_multi_thread()
190///         .worker_threads(2)
191///         .enable_all()
192///         .build()
193///         .unwrap()
194///         .block_on(async {
195///             println!("Hello world");
196///         })
197/// }
198/// ```
199///
200/// ### Configure the runtime to start with time paused
201///
202/// ```ignore
203/// #[tokio::main(flavor = "current_thread", start_paused = true)]
204/// async fn main() {
205///     println!("Hello world");
206/// }
207/// ```
208///
209/// Equivalent code not using `#[tokio::main]`
210///
211/// ```ignore
212/// fn main() {
213///     tokio::runtime::Builder::new_current_thread()
214///         .enable_all()
215///         .start_paused(true)
216///         .build()
217///         .unwrap()
218///         .block_on(async {
219///             println!("Hello world");
220///         })
221/// }
222/// ```
223///
224/// Note that `start_paused` requires the `test-util` feature to be enabled.
225///
226/// ### Rename package
227///
228/// ```ignore
229/// use tokio as tokio1;
230///
231/// #[tokio1::main(crate = "tokio1")]
232/// async fn main() {
233///     println!("Hello world");
234/// }
235/// ```
236///
237/// Equivalent code not using `#[tokio::main]`
238///
239/// ```ignore
240/// use tokio as tokio1;
241///
242/// fn main() {
243///     tokio1::runtime::Builder::new_multi_thread()
244///         .enable_all()
245///         .build()
246///         .unwrap()
247///         .block_on(async {
248///             println!("Hello world");
249///         })
250/// }
251/// ```
252///
253/// ### Configure unhandled panic behavior
254///
255/// Available options are `shutdown_runtime` and `ignore`. For more details, see
256/// [`Builder::unhandled_panic`].
257///
258/// This option is only compatible with the `current_thread` runtime.
259///
260/// ```no_run, ignore
261/// # #![allow(unknown_lints, unexpected_cfgs)]
262/// #[cfg(tokio_unstable)]
263/// #[tokio::main(flavor = "current_thread", unhandled_panic = "shutdown_runtime")]
264/// async fn main() {
265///     let _ = tokio::spawn(async {
266///         panic!("This panic will shutdown the runtime.");
267///     }).await;
268/// }
269/// # #[cfg(not(tokio_unstable))]
270/// # fn main() { }
271/// ```
272///
273/// Equivalent code not using `#[tokio::main]`
274///
275/// ```no_run, ignore
276/// # #![allow(unknown_lints, unexpected_cfgs)]
277/// #[cfg(tokio_unstable)]
278/// fn main() {
279///     tokio::runtime::Builder::new_current_thread()
280///         .enable_all()
281///         .unhandled_panic(UnhandledPanic::ShutdownRuntime)
282///         .build()
283///         .unwrap()
284///         .block_on(async {
285///             let _ = tokio::spawn(async {
286///                 panic!("This panic will shutdown the runtime.");
287///             }).await;
288///         })
289/// }
290/// # #[cfg(not(tokio_unstable))]
291/// # fn main() { }
292/// ```
293///
294/// **Note**: This option depends on Tokio's [unstable API][unstable]. See [the
295/// documentation on unstable features][unstable] for details on how to enable
296/// Tokio's unstable features.
297///
298/// [`Builder::unhandled_panic`]: ../tokio/runtime/struct.Builder.html#method.unhandled_panic
299/// [unstable]: ../tokio/index.html#unstable-features
300#[proc_macro_attribute]
301pub fn main(_args: TokenStream, item: TokenStream) -> TokenStream {
302    let input = parse_macro_input!(item as syn::ItemFn);
303
304    println!("{}", quote! { #input });
305    let mut fn_body = input.block.clone();
306    let fn_attrs = input.attrs.clone();
307    let fn_vis = input.vis.clone();
308    let _fn_sig = input.sig.clone();
309
310    let output = if cfg!(feature = "hot_reloading") {
311        quote! {
312            async fn __internal_main() -> Result<(), Box<dyn std::error::Error>> {
313                #fn_body
314
315                Ok::<(), Box<dyn std::error::Error>>(())
316            }
317
318            #(#fn_attrs)*
319            #fn_vis fn main() {
320                ::tokio::runtime::Builder::new_multi_thread()
321                    .enable_all()
322                    .build()
323                    .expect("Failed building the Runtime")
324                    .block_on(dioxus_devtools::serve_subsecond(__internal_main));
325            }
326        }
327    } else {
328        fn_body
329            .stmts
330            .push(parse_quote!({ Ok::<(), Box<dyn std::error::Error>>(()) }));
331
332        quote! {
333            #(#fn_attrs)*
334            #fn_vis fn main() {
335                ::tokio::runtime::Builder::new_multi_thread()
336                    .enable_all()
337                    .build()
338                    .expect("Failed building the Runtime")
339                    .block_on( async #fn_body );
340            }
341        }
342    };
343
344    output.into()
345}