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/// # OpenAPI
68///
69/// Optionally annotate the state and structures generated for automatic OpenAPI document
70/// generation.
71///
72/// ```rust,ignore
73/// #[stately::state(openapi)]
74/// pub struct AppState {
75/// pipelines: Pipeline,
76/// }
77/// ```
78///
79/// This generates a namespaced module (e.g., `axum_api`) with:
80/// - Concrete response types with OpenAPI schemas
81/// - Handler functions with OpenAPI path annotations
82/// - A router function
83/// - OpenAPI documentation attributes
84///
85/// # Generated Code
86///
87/// This generates:
88/// - `StateEntry` enum with variants for each entity type
89/// - `Entity` enum wrapping each entity for type erasure
90/// - The state struct with collection fields
91/// - (Optional) OpenAPI annotation
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.), providing the CRUD endpoints
99/// and events over `axum` APIs.
100///
101/// # Example
102///
103/// ```rust,ignore
104/// use std::sync::Arc;
105/// use tokio::sync::RwLock;
106/// use stately_derive::{state, axum_api};
107///
108/// #[stately::entity]
109/// pub struct Pipeline {
110/// pub name: String,
111/// pub source: Link<SourceConfig>,
112/// }
113///
114/// #[state(openapi)]
115/// pub struct AppState {
116/// pipelines: Pipeline,
117/// }
118///
119/// #[axum_api(AppState, openapi(components = [Pipeline]))]
120/// pub struct ApiState {
121/// // Your additional dependencies
122/// pub db_pool: PgPool,
123/// pub config: Config,
124/// }
125///
126/// // Use the generated API
127/// use api::ApiState;
128///
129/// let api_state = ApiState {
130/// app: Arc::new(RwLock::new(AppState::new())),
131/// db_pool: pool,
132/// config: cfg,
133/// };
134///
135/// let app = ApiState::router().with_state(api_state);
136/// ```
137///
138/// # Generated Code
139///
140/// This generates, in scope of the annotated api state:
141/// - Response types (`ListResponse`, `EntityResponse`, `OperationResponse`, etc.)
142/// - Handler functions for all CRUD operations
143/// - Associated methods on the struct:
144/// - `ApiState::router()` function returning `Router<S>`
145/// - `ApiState::event_middleware(...)` function to listen for CRUD events
146/// - OpenAPI annotations providing an OpenAPI doc
147///
148/// You can create multiple API structs for different purposes (public API, admin API, etc.),
149/// each with their own application state.
150#[proc_macro_attribute]
151pub fn axum_api(attr: TokenStream, item: TokenStream) -> TokenStream {
152 axum_api::generate(attr, item)
153}