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}