evento-macro
Procedural macros for the Evento event sourcing framework.
Overview
This crate provides macros that eliminate boilerplate when building event-sourced applications. It generates trait implementations, handler structs, and serialization code automatically.
Installation
This crate is typically used through the main evento crate with the macro feature enabled (on by default):
[]
= "2"
Or use this crate directly:
[]
= "2"
Macros
| Macro | Type | Purpose |
|---|---|---|
#[evento::aggregator] |
Attribute | Transform enum into event structs |
#[evento::handler] |
Attribute | Create projection handler from async function |
#[evento::subscription] |
Attribute | Create subscription handler for specific events |
#[evento::subscription_all] |
Attribute | Create subscription handler for all events |
#[evento::projection] |
Attribute | Add cursor field and implement ProjectionCursor |
#[evento::snapshot] |
Attribute | Implement snapshot restoration |
#[derive(Cursor)] |
Derive | Generate cursor struct and trait implementations |
#[evento::debug_handler] |
Attribute | Like handler with debug output |
#[evento::debug_snapshot] |
Attribute | Like snapshot with debug output |
Usage
Defining Events with #[evento::aggregator]
Transform an enum into individual event structs with all required trait implementations:
This generates:
- Individual structs:
AccountOpened,MoneyDeposited,MoneyWithdrawn Aggregatortrait implementation (providesaggregator_type())Eventtrait implementation (providesevent_name())- Automatic derives:
Debug,Clone,PartialEq,Default, and bitcode serialization
The aggregator type is formatted as "{package_name}/{enum_name}", e.g., "bank/BankAccount".
Additional Derives
Pass additional derives as arguments:
Projection State with #[evento::projection]
Automatically add cursor tracking to projection structs:
// Generates:
// - Adds `pub cursor: String` field
// - Implements `ProjectionCursor` trait
// - Adds `Default` and `Clone` derives
Creating Projection Handlers with #[evento::handler]
Projection handlers are used to build read models by replaying events:
use Event;
async
// Register with a projection
let result =
.handler
.execute
.await?;
The macro generates:
HandleMoneyDepositedHandlerstructhandle_money_deposited()constructor functionprojection::Handler<AccountBalanceView>trait implementation
Creating Subscription Handlers with #[evento::subscription]
Subscription handlers process events in real-time with side effects:
use ;
async
// Register with a subscription
let subscription = new
.handler
.routing_key
.start
.await?;
Handling All Events with #[evento::subscription_all]
Handle all events from an aggregate type without deserializing:
use ;
async
Snapshot Restoration with #[evento::snapshot]
Implement snapshot restoration for projections:
use RwContext;
use HashMap;
async
Debug Macros
Use #[evento::debug_handler] or #[evento::debug_snapshot] to output the generated code to a file for inspection:
async
// Generated code written to: target/evento_debug_handler_macro.rs
Requirements
When using these macros, your types must meet certain requirements:
- Events (from
#[aggregator]): Traits are automatically derived - Projections: Must implement
Default,Send,Sync,Clone - Projection handlers: Must be
asyncand returnanyhow::Result<()> - Subscription handlers: Must be
async, takeContextfirst, and returnanyhow::Result<()>
Serialization
Events are serialized using bitcode for compact binary representation. The #[aggregator] macro automatically adds the required bitcode derives:
bitcode::Encodebitcode::Decode
Minimum Supported Rust Version
Rust 1.75 or later.
Safety
This crate uses #![forbid(unsafe_code)] to ensure everything is implemented in 100% safe Rust.
License
See the LICENSE file in the repository root.