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