fastn_context_macros/lib.rs
1//! # fastn-context-macros
2//!
3//! Procedural macros for the `fastn-context` crate.
4//!
5//! This crate provides the `#[main]` attribute macro that simplifies setting up
6//! fastn applications with automatic context management.
7//!
8//! ## Usage
9//!
10//! Add the `#[main]` attribute to your async main function to automatically set up
11//! the tokio runtime and global context:
12//!
13//! ```rust
14//! use fastn_context::main;
15//!
16//! #[main]
17//! async fn main() {
18//! // Your application code here
19//! // Global context is automatically available via fastn_context::global()
20//! }
21//! ```
22//!
23//! This is equivalent to:
24//!
25//! ```rust
26//! #[tokio::main]
27//! async fn main() {
28//! // Manual setup would go here
29//! }
30//! ```
31//!
32//! But with automatic context initialization and cleanup.
33
34use proc_macro::TokenStream;
35use quote::quote;
36use syn::{ItemFn, parse_macro_input};
37
38/// Main function attribute macro for fastn applications with context support.
39///
40/// This macro transforms your async main function to automatically set up the tokio runtime
41/// and initialize global context management. It's the recommended way to start fastn applications.
42///
43/// ## Features
44///
45/// - Automatically creates a multi-threaded tokio runtime
46/// - Enables all tokio features (time, net, fs, etc.)
47/// - Sets up global context management
48/// - Provides clean error handling
49///
50/// ## Example
51///
52/// ```rust
53/// use fastn_context::main;
54///
55/// #[main]
56/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
57/// println!("Application starting");
58///
59/// // Global context is available
60/// let ctx = fastn_context::global().await;
61/// println!("App context: {}", ctx.name());
62///
63/// Ok(())
64/// }
65/// ```
66///
67/// ## Return Types
68///
69/// Your main function can return:
70/// - `()` - No error handling
71/// - `Result<(), E>` where `E: std::error::Error` - With error handling
72///
73/// ## Generated Code
74///
75/// The macro generates a standard `fn main()` that creates the tokio runtime and calls
76/// your async function. Error handling is automatically provided.
77#[proc_macro_attribute]
78pub fn main(_args: TokenStream, input: TokenStream) -> TokenStream {
79 let input_fn = parse_macro_input!(input as ItemFn);
80
81 let user_fn_name = syn::Ident::new("__fastn_user_main", proc_macro2::Span::call_site());
82 let fn_block = &input_fn.block;
83 let fn_attrs = &input_fn.attrs;
84 let fn_vis = &input_fn.vis;
85
86 quote! {
87 #(#fn_attrs)*
88 #fn_vis fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
89 // Initialize tokio runtime
90 tokio::runtime::Builder::new_multi_thread()
91 .enable_all()
92 .build()?
93 .block_on(async {
94 // Global context automatically created
95
96 // Call user's main function
97 let result = #user_fn_name().await;
98
99 result
100 })
101 }
102
103 async fn #user_fn_name() -> std::result::Result<(), Box<dyn std::error::Error>> #fn_block
104 }
105 .into()
106}