eventcore_macros/lib.rs
1//! Procedural macros for the EventCore event sourcing library.
2//!
3//! This crate provides derive macros and attribute macros to reduce boilerplate
4//! when implementing commands and other EventCore patterns.
5
6use proc_macro::TokenStream;
7use syn::{parse_macro_input, DeriveInput};
8
9mod command;
10mod stream_set;
11mod utils;
12
13use command::expand_derive_command;
14
15/// Derive macro for implementing the CommandStreams trait.
16///
17/// This macro generates a complete implementation of `CommandStreams` based on
18/// fields marked with `#[stream]`. You only need to implement `CommandLogic`
19/// for your domain logic.
20///
21/// # Example
22///
23/// ```ignore
24/// use eventcore_macros::Command;
25/// use eventcore::{CommandLogic, prelude::*};
26///
27/// #[derive(Command, Clone)]
28/// struct TransferMoney {
29/// #[stream]
30/// from_account: StreamId,
31/// #[stream]
32/// to_account: StreamId,
33/// amount: Money,
34/// }
35///
36/// #[async_trait]
37/// impl CommandLogic for TransferMoney {
38/// type State = AccountBalances;
39/// type Event = BankingEvent;
40///
41/// fn apply(&self, state: &mut Self::State, event: &StoredEvent<Self::Event>) {
42/// // Your event folding logic
43/// }
44///
45/// async fn handle(
46/// &self,
47/// read_streams: ReadStreams<Self::StreamSet>,
48/// state: Self::State,
49/// input: Self::Input,
50/// stream_resolver: &mut StreamResolver,
51/// ) -> CommandResult<Vec<StreamWrite<Self::StreamSet, Self::Event>>> {
52/// // Your business logic
53/// }
54/// }
55/// ```
56///
57/// This automatically generates:
58/// - Complete `CommandStreams` trait implementation
59/// - `type Input = Self` (the command struct serves as input)
60/// - `type StreamSet = TransferMoneyStreamSet` (phantom type for stream access)
61/// - `fn read_streams()` implementation extracting from `#[stream]` fields
62#[proc_macro_derive(Command, attributes(stream))]
63pub fn derive_command(input: TokenStream) -> TokenStream {
64 let input = parse_macro_input!(input as DeriveInput);
65
66 expand_derive_command(input)
67 .unwrap_or_else(|err| err.to_compile_error())
68 .into()
69}
70
71/// Internal module for testing macro expansion.
72#[cfg(test)]
73mod tests {
74 // Note: Procedural macros cannot be tested directly in unit tests
75 // because they require the proc macro bridge which is only available
76 // when the macro is actually being used as a procedural macro.
77 //
78 // Proper testing should be done through integration tests using
79 // the trybuild crate or by testing the internal functions directly.
80
81 #[test]
82 fn test_macro_crate_compiles() {
83 // Simple test to ensure the crate compiles
84 // The test itself is the compilation check
85 let _placeholder = 1 + 1;
86 }
87}