stately_derive/
lib.rs

1//! Procedural macros for stately state management
2
3use proc_macro::TokenStream;
4
5mod axum_api;
6mod entity;
7mod state;
8
9/// Implements the `HasName` trait for an entity struct.
10///
11/// This macro provides flexible name resolution for entities. The `StateEntity` trait
12/// is automatically implemented by the `#[stately::state]` macro when the entity is
13/// added to a state struct.
14///
15/// # Attributes
16///
17/// - `#[stately::entity]` - Uses the default "name" field
18/// - `#[stately::entity(name_field = "field_name")]` - Uses a different field for the name
19/// - `#[stately::entity(name_method = "method_name")]` - Calls a method to get the name
20/// - `#[stately::entity(singleton)]` - For singleton entities, returns "default" as the name
21///
22/// # Examples
23///
24/// ```rust,ignore
25/// // Default: uses the "name" field
26/// #[stately::entity]
27/// pub struct Pipeline {
28///     pub name: String,
29///     pub source: Link<SourceConfig>,
30/// }
31///
32/// // Custom field name
33/// #[stately::entity(name_field = "identifier")]
34/// pub struct Config {
35///     identifier: String,
36/// }
37///
38/// // Custom method
39/// #[stately::entity(name_method = "get_name")]
40/// pub struct Task {
41///     id: String,
42/// }
43/// impl Task {
44///     fn get_name(&self) -> &str { &self.id }
45/// }
46/// ```
47#[proc_macro_attribute]
48pub fn entity(attr: TokenStream, item: TokenStream) -> TokenStream { entity::entity(attr, item) }
49
50/// Generates application state with entity collections.
51///
52/// # Syntax
53///
54/// ```rust,ignore
55/// #[stately::state]
56/// pub struct AppState {
57///     // Regular collections (many entities)
58///     pipelines: Pipeline,
59///     sources: SourceConfig,
60///
61///     // Singletons (one entity)
62///     #[singleton]
63///     parse_settings: BufferSettings,
64/// }
65/// ```
66///
67/// # API Generation
68///
69/// Optionally generate web API code by specifying the `api` attribute:
70///
71/// ```rust,ignore
72/// #[stately::state(api = ["axum"])]
73/// pub struct AppState {
74///     pipelines: Pipeline,
75/// }
76/// ```
77///
78/// This generates a namespaced module (e.g., `axum_api`) with:
79/// - Concrete response types with OpenAPI schemas
80/// - Handler functions with OpenAPI path annotations
81/// - A router function
82/// - An OpenAPI documentation struct
83///
84/// # Generated Code
85///
86/// This generates:
87/// - `StateEntry` enum with variants for each entity type
88/// - `Entity` enum wrapping each entity for type erasure
89/// - The state struct with collection fields
90/// - CRUD operation methods
91/// - (Optional) API-specific modules for web frameworks
92#[proc_macro_attribute]
93pub fn state(attr: TokenStream, item: TokenStream) -> TokenStream { state::state(attr, item) }
94
95/// Generates Axum API integration for a state wrapper struct.
96///
97/// This macro allows you to create custom API state structs that wrap your stately state
98/// along with additional dependencies (database pools, config, etc.).
99///
100/// # Requirements
101///
102/// - The struct must have exactly one field marked with `#[state]`
103/// - That field must be of type `Arc<RwLock<YourStateType>>`
104/// - Pass the state type name as the attribute argument
105///
106/// # Example
107///
108/// ```rust,ignore
109/// use std::sync::Arc;
110/// use tokio::sync::RwLock;
111/// use stately_derive::{state, axum_api};
112///
113/// #[state]
114/// pub struct AppState {
115///     pipelines: Pipeline,
116/// }
117///
118/// #[axum_api(AppState)]
119/// pub struct ApiState {
120///     #[state]
121///     pub app: Arc<RwLock<AppState>>,
122///
123///     // Your additional dependencies
124///     pub db_pool: PgPool,
125///     pub config: Config,
126/// }
127///
128/// // Use the generated API
129/// use api::{router, ApiDoc};
130///
131/// let api_state = ApiState {
132///     app: Arc::new(RwLock::new(AppState::new())),
133///     db_pool: pool,
134///     config: cfg,
135/// };
136///
137/// let app = router().with_state(api_state);
138/// ```
139///
140/// # Generated Code
141///
142/// This generates:
143/// - A `Clone` implementation for the struct
144/// - An `api` module containing:
145///   - Response types (`ListResponse`, `EntityResponse`, `OperationResponse`, etc.)
146///   - Handler functions for all CRUD operations
147///   - `router()` function returning `Router<YourStructName>`
148///   - `ApiDoc` struct for OpenAPI documentation
149///
150/// You can create multiple API structs for different purposes (public API, admin API, etc.),
151/// each with their own `api` module.
152#[proc_macro_attribute]
153pub fn axum_api(attr: TokenStream, item: TokenStream) -> TokenStream {
154    axum_api::generate(attr, item)
155}