allframe_macros/
lib.rs

1//! AllFrame Procedural Macros
2//!
3//! This crate provides compile-time code generation for AllFrame,
4//! including dependency injection, OpenAPI schema generation, and more.
5
6#![deny(warnings)]
7
8mod api;
9mod arch;
10mod cqrs;
11mod di;
12mod otel;
13
14use proc_macro::TokenStream;
15
16// Note: The `provide` attribute is handled directly by `di_container` macro
17// It doesn't need a separate proc_macro_attribute since it's consumed during
18// parsing
19
20/// Compile-time dependency injection container
21///
22/// Generates a container with automatic dependency resolution at compile time.
23///
24/// # Example
25/// ```ignore
26/// #[di_container]
27/// struct AppContainer {
28///     database: DatabaseService,
29///     repository: UserRepository,
30/// }
31///
32/// let container = AppContainer::new();
33/// ```
34#[proc_macro_attribute]
35pub fn di_container(attr: TokenStream, item: TokenStream) -> TokenStream {
36    let attr = proc_macro2::TokenStream::from(attr);
37    let item = proc_macro2::TokenStream::from(item);
38
39    di::di_container_impl(attr, item)
40        .unwrap_or_else(|err| err.to_compile_error())
41        .into()
42}
43
44/// API handler with auto OpenAPI generation
45///
46/// Generates OpenAPI 3.1 schema for the annotated function.
47///
48/// # Example
49/// ```ignore
50/// #[api_handler(path = "/users", method = "POST", description = "Create user")]
51/// async fn create_user(req: CreateUserRequest) -> CreateUserResponse {
52///     // handler implementation
53/// }
54///
55/// // Generated function:
56/// // fn create_user_openapi_schema() -> String { /* JSON schema */ }
57/// ```
58#[proc_macro_attribute]
59pub fn api_handler(attr: TokenStream, item: TokenStream) -> TokenStream {
60    let attr = proc_macro2::TokenStream::from(attr);
61    let item = proc_macro2::TokenStream::from(item);
62
63    api::api_handler_impl(attr, item)
64        .unwrap_or_else(|err| err.to_compile_error())
65        .into()
66}
67
68/// Marks a type as part of the Domain layer (Layer 1)
69///
70/// Domain entities contain pure business logic with no infrastructure
71/// dependencies.
72///
73/// # Example
74/// ```ignore
75/// #[domain]
76/// struct User {
77///     id: UserId,
78///     email: Email,
79/// }
80/// ```
81#[proc_macro_attribute]
82pub fn domain(attr: TokenStream, item: TokenStream) -> TokenStream {
83    let attr = proc_macro2::TokenStream::from(attr);
84    let item = proc_macro2::TokenStream::from(item);
85
86    arch::domain_impl(attr, item)
87        .unwrap_or_else(|err| err.to_compile_error())
88        .into()
89}
90
91/// Marks a type as part of the Repository layer (Layer 2)
92///
93/// Repositories handle data access and can depend on Domain entities.
94///
95/// # Example
96/// ```ignore
97/// #[repository]
98/// trait UserRepository: Send + Sync {
99///     async fn find(&self, id: UserId) -> Option<User>;
100/// }
101/// ```
102#[proc_macro_attribute]
103pub fn repository(attr: TokenStream, item: TokenStream) -> TokenStream {
104    let attr = proc_macro2::TokenStream::from(attr);
105    let item = proc_macro2::TokenStream::from(item);
106
107    arch::repository_impl(attr, item)
108        .unwrap_or_else(|err| err.to_compile_error())
109        .into()
110}
111
112/// Marks a type as part of the Use Case layer (Layer 3)
113///
114/// Use cases orchestrate application logic and can depend on Repositories and
115/// Domain.
116///
117/// # Example
118/// ```ignore
119/// #[use_case]
120/// struct GetUserUseCase {
121///     repo: Arc<dyn UserRepository>,
122/// }
123/// ```
124#[proc_macro_attribute]
125pub fn use_case(attr: TokenStream, item: TokenStream) -> TokenStream {
126    let attr = proc_macro2::TokenStream::from(attr);
127    let item = proc_macro2::TokenStream::from(item);
128
129    arch::use_case_impl(attr, item)
130        .unwrap_or_else(|err| err.to_compile_error())
131        .into()
132}
133
134/// Marks a type as part of the Handler layer (Layer 4)
135///
136/// Handlers are entry points (HTTP/gRPC/GraphQL) and can only depend on Use
137/// Cases. Handlers CANNOT depend on Repositories directly - they must go
138/// through Use Cases.
139///
140/// # Example
141/// ```ignore
142/// #[handler]
143/// struct GetUserHandler {
144///     use_case: Arc<GetUserUseCase>,
145/// }
146/// ```
147#[proc_macro_attribute]
148pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
149    let attr = proc_macro2::TokenStream::from(attr);
150    let item = proc_macro2::TokenStream::from(item);
151
152    arch::handler_impl(attr, item)
153        .unwrap_or_else(|err| err.to_compile_error())
154        .into()
155}
156
157/// Marks a struct as a Command (CQRS write operation)
158///
159/// Commands represent write operations that change state and produce events.
160///
161/// # Example
162/// ```ignore
163/// #[command]
164/// struct CreateUserCommand {
165///     email: String,
166///     name: String,
167/// }
168/// ```
169#[proc_macro_attribute]
170pub fn command(attr: TokenStream, item: TokenStream) -> TokenStream {
171    let attr = proc_macro2::TokenStream::from(attr);
172    let item = proc_macro2::TokenStream::from(item);
173
174    cqrs::command_impl(attr, item)
175        .unwrap_or_else(|err| err.to_compile_error())
176        .into()
177}
178
179/// Marks a struct as a Query (CQRS read operation)
180///
181/// Queries represent read operations that don't change state.
182///
183/// # Example
184/// ```ignore
185/// #[query]
186/// struct GetUserQuery {
187///     user_id: String,
188/// }
189/// ```
190#[proc_macro_attribute]
191pub fn query(attr: TokenStream, item: TokenStream) -> TokenStream {
192    let attr = proc_macro2::TokenStream::from(attr);
193    let item = proc_macro2::TokenStream::from(item);
194
195    cqrs::query_impl(attr, item)
196        .unwrap_or_else(|err| err.to_compile_error())
197        .into()
198}
199
200/// Marks an enum or struct as an Event
201///
202/// Events represent immutable facts that have occurred in the system.
203///
204/// # Example
205/// ```ignore
206/// #[event]
207/// enum UserEvent {
208///     Created { user_id: String, email: String },
209///     Updated { user_id: String, email: String },
210/// }
211/// ```
212#[proc_macro_attribute]
213pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream {
214    let attr = proc_macro2::TokenStream::from(attr);
215    let item = proc_macro2::TokenStream::from(item);
216
217    cqrs::event_impl(attr, item)
218        .unwrap_or_else(|err| err.to_compile_error())
219        .into()
220}
221
222/// Marks a function as a Command Handler
223///
224/// Command handlers process commands and produce events.
225///
226/// # Example
227/// ```ignore
228/// #[command_handler]
229/// async fn handle_create_user(cmd: CreateUserCommand) -> Result<Vec<Event>, String> {
230///     Ok(vec![Event::UserCreated { ... }])
231/// }
232/// ```
233#[proc_macro_attribute]
234pub fn command_handler(attr: TokenStream, item: TokenStream) -> TokenStream {
235    let attr = proc_macro2::TokenStream::from(attr);
236    let item = proc_macro2::TokenStream::from(item);
237
238    cqrs::command_handler_impl(attr, item)
239        .unwrap_or_else(|err| err.to_compile_error())
240        .into()
241}
242
243/// Marks a function as a Query Handler
244///
245/// Query handlers process queries and return data from projections.
246///
247/// # Example
248/// ```ignore
249/// #[query_handler]
250/// async fn handle_get_user(query: GetUserQuery) -> Result<Option<User>, String> {
251///     Ok(Some(user))
252/// }
253/// ```
254#[proc_macro_attribute]
255pub fn query_handler(attr: TokenStream, item: TokenStream) -> TokenStream {
256    let attr = proc_macro2::TokenStream::from(attr);
257    let item = proc_macro2::TokenStream::from(item);
258
259    cqrs::query_handler_impl(attr, item)
260        .unwrap_or_else(|err| err.to_compile_error())
261        .into()
262}
263
264/// Marks a function to be automatically traced with OpenTelemetry
265///
266/// Automatically creates spans with proper context propagation.
267///
268/// # Example
269/// ```ignore
270/// #[traced]
271/// async fn fetch_user(user_id: String) -> Result<User, Error> {
272///     // Span created automatically with name "fetch_user"
273///     // Span includes function arguments as attributes
274///     Ok(user)
275/// }
276/// ```
277#[proc_macro_attribute]
278pub fn traced(attr: TokenStream, item: TokenStream) -> TokenStream {
279    let attr = proc_macro2::TokenStream::from(attr);
280    let item = proc_macro2::TokenStream::from(item);
281
282    otel::traced_impl(attr, item)
283        .unwrap_or_else(|err| err.to_compile_error())
284        .into()
285}
286
287#[cfg(test)]
288mod tests {
289    #[test]
290    fn test_macros_crate_compiles() {
291        assert!(true);
292    }
293}