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}