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}