verdure_macros/
lib.rs

1//! Verdure Procedural Macros - Annotation Processing for the Verdure Ecosystem
2//!
3//! This crate provides the procedural macros that enable Verdure's declarative,
4//! annotation-driven programming model. These macros power the entire Verdure ecosystem
5//! by automatically generating the boilerplate code needed for dependency injection,
6//! component registration, and framework integration.
7//!
8//! As part of the Verdure ecosystem, these macros work seamlessly across all framework
9//! modules - from web controllers to data repositories to security components.
10//!
11//! # Macros
12//!
13//! * `#[derive(Component)]` - Automatically implements `ComponentInitializer` and registers the component
14//!
15//! # Attributes
16//!
17//! * `#[autowired]` - Marks a field for automatic dependency injection
18//! * `#[component]` - Provides component configuration options
19//!
20//! # Examples
21//!
22//! ```rust
23//! use verdure::Component;
24//! use std::sync::Arc;
25//!
26//! #[derive(Component)]
27//! struct DatabaseService {
28//!     connection_string: String,
29//! }
30//!
31//! #[derive(Component)]
32//! struct UserService {
33//!     #[autowired]
34//!     db: Arc<DatabaseService>,
35//!     cache_size: usize,
36//! }
37//! ```
38//!
39//! The `#[derive(Component)]` macro will:
40//!
41//! 1. Generate an implementation of `ComponentInitializer`
42//! 2. Register the component with the global component registry
43//! 3. Automatically handle dependency injection for `#[autowired]` fields
44//! 4. Initialize non-autowired fields using `Default::default()` or `None` for `Option<T>`
45
46mod component;
47mod configuration;
48
49use proc_macro::TokenStream;
50use syn::{DeriveInput, parse_macro_input};
51
52/// Derive macro for automatic component registration and dependency injection
53///
54/// The `Component` derive macro automatically implements the `ComponentInitializer` trait
55/// and registers the component with the IoC container. It handles dependency injection
56/// for fields marked with `#[autowired]` and provides sensible defaults for other fields.
57///
58/// # Attributes
59///
60/// * `#[autowired]` - Marks a field for automatic dependency injection. The field must be of type `Arc<T>`
61/// * `#[component(scope = "...")]` - Sets the component scope (defaults to `Singleton`)
62///
63/// # Field Initialization Rules
64///
65/// 1. **Autowired fields**: Automatically injected by the container
66/// 2. **Option fields**: Initialized to `None`
67/// 3. **Other fields**: Initialized using `Default::default()`
68///
69/// # Examples
70///
71/// ```rust
72/// use verdure::Component;
73/// use std::sync::Arc;
74///
75/// // Simple component with no dependencies
76/// #[derive(Component)]
77/// struct ConfigService {
78///     config_path: String, // Will be initialized with Default::default() = ""
79///     port: u16,           // Will be initialized with Default::default() = 0
80/// }
81///
82/// // Component with dependencies
83/// #[derive(Component)]
84/// struct DatabaseService {
85///     #[autowired]
86///     config: Arc<ConfigService>, // Automatically injected
87///     optional_cache: Option<String>, // Initialized to None
88///     connection_pool_size: usize,    // Default::default() = 0
89/// }
90///
91/// // Component with custom scope
92/// #[derive(Component)]
93/// #[component(scope = "Prototype")]
94/// struct RequestHandler {
95///     #[autowired]
96///     db: Arc<DatabaseService>,
97///     request_id: String,
98/// }
99/// ```
100///
101/// # Generated Code
102///
103/// The macro generates implementations of `ComponentInitializer` and registers the component
104/// with the global registry using the `inventory` crate.
105///
106/// # Panics
107///
108/// The macro will produce compile-time errors in the following cases:
109///
110/// * Applying to enums or unions (only structs with named fields are supported)
111/// * Using `#[autowired]` on fields that are not `Arc<T>`
112/// * Invalid syntax in component attributes
113#[proc_macro_derive(Component, attributes(component, autowired))]
114pub fn component_derive(input: TokenStream) -> TokenStream {
115    let ast = parse_macro_input!(input as DeriveInput);
116    component::impl_component_derive(&ast).into()
117}
118
119#[proc_macro_derive(Configuration, attributes(configuration, config_default, config_default_t))]
120pub fn configuration_derive(input: TokenStream) -> TokenStream {
121    let ast = parse_macro_input!(input as DeriveInput);
122    configuration::impl_configuration_derive(&ast).into()
123}