discern/macros.rs
1//! The `macros` module provides convenient macros for creating and registering command and query buses.
2//!
3//! This module includes macros for initializing `CommandBus` and `QueryBus` instances with their respective
4//! handlers, as well as macros for creating and registering command and query handler registries.
5//!
6//! Key macros:
7//!
8//! - [command_bus](crate::command_bus): Creates a `CommandBus` and registers handlers.
9//! - [command_registry](crate::command_registry): Creates a `CommandHandlerRegistry` and registers handlers.
10//! - [query_bus](crate::query_bus): Creates a `QueryBus` and registers handlers.
11//! - [query_registry](crate::query_registry): Creates a `QueryHandlerRegistry` and registers handlers.
12
13/// A macro for creating a `CommandBus` instance.
14///
15/// This macro provides a convenient way to initialize a `CommandBus` and register multiple
16/// command handlers at once.
17///
18/// # Usage
19///
20/// You can use this macro in two ways:
21///
22/// 1. **Providing only handlers:**
23///
24/// ```
25/// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
26/// # rt.block_on(async {
27/// # use discern::command::Command;
28/// # use discern::async_trait;
29/// # use discern::command::CommandHandler;
30/// #
31/// # #[derive(Debug)]
32/// # enum CreateUserError {
33/// # UsernameAlreadyExists,
34/// # EmailAlreadyExists,
35/// # }
36/// #
37/// # #[derive(Debug)]
38/// # struct CreateUserCommand {
39/// # username: String,
40/// # email: String,
41/// # }
42/// #
43/// # impl Command for CreateUserCommand {
44/// # // The identifier of the newly created user.
45/// # type Metadata = u64;
46/// # // The error type that is returned if the command fails.
47/// # type Error = CreateUserError;
48/// # }
49/// #
50/// # struct CreateUserCommandHandler;
51/// #
52/// # #[async_trait]
53/// # impl CommandHandler<CreateUserCommand> for CreateUserCommandHandler {
54/// # async fn handle(&self, command: CreateUserCommand) -> Result<u64, CreateUserError> {
55/// # // Create a new user.
56/// # Ok(1)
57/// # }
58/// # }
59/// use discern::command_bus;
60///
61/// let command_bus = command_bus! {
62/// CreateUserCommandHandler { /* ... */ },
63/// };
64/// #
65/// # let command = CreateUserCommand {
66/// # username: "alice".to_string(),
67/// # email: "alice@localhost".to_string(),
68/// # };
69/// #
70/// # let result = command_bus.dispatch(command).await;
71/// # match result {
72/// # Ok(user_id) => {
73/// # assert_eq!(user_id, 1);
74/// # println!("User created with id: {}", user_id);
75/// # },
76/// # Err(err) => {
77/// # assert!(false);
78/// # eprintln!("Failed to create user: {:?}", err);
79/// # }
80/// # }
81/// # });
82/// ```
83///
84/// This assumes that the types of the handlers can be inferred automatically.
85///
86/// 2. **Providing type-handler pairs:**
87///
88/// ```
89/// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
90/// # rt.block_on(async {
91/// # use discern::command::Command;
92/// # use discern::async_trait;
93/// # use discern::command::CommandHandler;
94/// #
95/// # #[derive(Debug)]
96/// # enum CreateUserError {
97/// # UsernameAlreadyExists,
98/// # EmailAlreadyExists,
99/// # }
100/// #
101/// # #[derive(Debug)]
102/// # struct CreateUserCommand {
103/// # username: String,
104/// # email: String,
105/// # }
106/// #
107/// # impl Command for CreateUserCommand {
108/// # // The identifier of the newly created user.
109/// # type Metadata = u64;
110/// # // The error type that is returned if the command fails.
111/// # type Error = CreateUserError;
112/// # }
113/// #
114/// # struct CreateUserCommandHandler;
115/// #
116/// # #[async_trait]
117/// # impl CommandHandler<CreateUserCommand> for CreateUserCommandHandler {
118/// # async fn handle(&self, command: CreateUserCommand) -> Result<u64, CreateUserError> {
119/// # // Create a new user.
120/// # Ok(1)
121/// # }
122/// # }
123/// use discern::command_bus;
124///
125/// let command_bus = command_bus! {
126/// CreateUserCommand => CreateUserCommandHandler { /* ... */ },
127/// };
128/// #
129/// # let command = CreateUserCommand {
130/// # username: "alice".to_string(),
131/// # email: "alice@localhost".to_string(),
132/// # };
133/// #
134/// # let result = command_bus.dispatch(command).await;
135/// # match result {
136/// # Ok(user_id) => {
137/// # assert_eq!(user_id, 1);
138/// # println!("User created with id: {}", user_id);
139/// # },
140/// # Err(err) => {
141/// # assert!(false);
142/// # eprintln!("Failed to create user: {:?}", err);
143/// # }
144/// # }
145/// # });
146/// ```
147/// This explicitly specifies the command type associated with each handler.
148///
149/// # See Also
150///
151/// - [CommandBus](crate::command::CommandBus)
152#[macro_export]
153macro_rules! command_bus {
154 () => {{
155 $crate::command::CommandBus::new($crate::registry::CommandHandlerRegistry::new())
156 }};
157 ($($handler:expr),*$(,)?) => {{
158 let mut command_handler_registry = $crate::registry::CommandHandlerRegistry::new();
159 $(command_handler_registry.register($handler);)*
160 $crate::command::CommandBus::new(command_handler_registry)
161 }};
162 ($($command:ty => $handler:expr),*$(,)?) => {{
163 let mut command_handler_registry = $crate::registry::CommandHandlerRegistry::new();
164 $(command_handler_registry.register::<$command>($handler);)*
165 $crate::command::CommandBus::new(command_handler_registry)
166 }};
167 }
168
169/// A macro for creating a `CommandHandlerRegistry` instance.
170///
171/// This macro provides a convenient way to initialize a `CommandHandlerRegistry` and register multiple
172/// command handlers at once.
173///
174/// # Usage
175///
176/// You can use this macro in two ways:
177///
178/// 1. **Providing only handlers:**
179///
180/// ```
181/// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
182/// # rt.block_on(async {
183/// # use discern::command::Command;
184/// # use discern::async_trait;
185/// # use discern::command::CommandHandler;
186/// #
187/// # #[derive(Debug)]
188/// # enum CreateUserError {
189/// # UsernameAlreadyExists,
190/// # EmailAlreadyExists,
191/// # }
192/// #
193/// # #[derive(Debug)]
194/// # struct CreateUserCommand {
195/// # username: String,
196/// # email: String,
197/// # }
198/// #
199/// # impl Command for CreateUserCommand {
200/// # // The identifier of the newly created user.
201/// # type Metadata = u64;
202/// # // The error type that is returned if the command fails.
203/// # type Error = CreateUserError;
204/// # }
205/// #
206/// # struct CreateUserCommandHandler;
207/// #
208/// # #[async_trait]
209/// # impl CommandHandler<CreateUserCommand> for CreateUserCommandHandler {
210/// # async fn handle(&self, command: CreateUserCommand) -> Result<u64, CreateUserError> {
211/// # // Create a new user.
212/// # Ok(1)
213/// # }
214/// # }
215/// use discern::command_registry;
216///
217/// let command_registry = command_registry! {
218/// CreateUserCommandHandler { /* ... */ },
219/// };
220/// # });
221/// ```
222///
223/// This assumes that the types of the handlers can be inferred automatically.
224///
225/// 2. **Providing type-handler pairs:**
226///
227/// ```
228/// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
229/// # rt.block_on(async {
230/// # use discern::command::Command;
231/// # use discern::async_trait;
232/// # use discern::command::CommandHandler;
233/// #
234/// # #[derive(Debug)]
235/// # enum CreateUserError {
236/// # UsernameAlreadyExists,
237/// # EmailAlreadyExists,
238/// # }
239/// #
240/// # #[derive(Debug)]
241/// # struct CreateUserCommand {
242/// # username: String,
243/// # email: String,
244/// # }
245/// #
246/// # impl Command for CreateUserCommand {
247/// # // The identifier of the newly created user.
248/// # type Metadata = u64;
249/// # // The error type that is returned if the command fails.
250/// # type Error = CreateUserError;
251/// # }
252/// #
253/// # struct CreateUserCommandHandler;
254/// #
255/// # #[async_trait]
256/// # impl CommandHandler<CreateUserCommand> for CreateUserCommandHandler {
257/// # async fn handle(&self, command: CreateUserCommand) -> Result<u64, CreateUserError> {
258/// # // Create a new user.
259/// # Ok(1)
260/// # }
261/// # }
262/// use discern::command_registry;
263///
264/// let command_registry = command_registry! {
265/// CreateUserCommand => CreateUserCommandHandler { /* ... */ },
266/// };
267/// # });
268/// ```
269/// This explicitly specifies the command type associated with each handler.
270///
271/// # See Also
272///
273/// - [CommandHandlerRegistry](crate::registry::CommandHandlerRegistry)
274#[macro_export]
275macro_rules! command_registry {
276 () => {{
277 $crate::command::CommandHandlerRegistry::new()
278 }};
279 ($($handler:expr),*$(,)?) => {{
280 let mut command_handler_registry = $crate::registry::CommandHandlerRegistry::new();
281 $(command_handler_registry.register($handler);)*
282 command_handler_registry
283 }};
284 ($($command:ty => $handler:expr),*$(,)?) => {{
285 let mut command_handler_registry = $crate::registry::CommandHandlerRegistry::new();
286 $(command_handler_registry.register::<$command>($handler);)*
287 command_handler_registry
288 }};
289 }
290/// A macro for creating a `QueryBus` instance.
291///
292/// This macro provides a convenient way to initialize a `QueryBus` and register multiple
293/// query handlers at once.
294///
295/// # Usage
296///
297/// You can use this macro in two ways:
298///
299/// 1. **Providing only handlers:**
300///
301/// ```
302/// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
303/// # rt.block_on(async {
304/// # use discern::query::Query;
305/// # use discern::async_trait;
306/// # use discern::query::QueryHandler;
307/// #
308/// # #[derive(Debug)]
309/// # struct GetUserQuery {
310/// # user_id: u64,
311/// # }
312/// #
313/// # impl Query for GetUserQuery {
314/// # type Output = String;
315/// # type Error = std::io::Error;
316/// # }
317/// #
318/// # struct GetUserQueryHandler;
319/// #
320/// # #[async_trait]
321/// # impl QueryHandler<GetUserQuery> for GetUserQueryHandler {
322/// # async fn handle(&self, query: GetUserQuery) -> Result<String, std::io::Error> {
323/// # Ok("Alice".to_string())
324/// # }
325/// # }
326/// use discern::query_bus;
327///
328/// let query_bus = query_bus! {
329/// GetUserQueryHandler { /* ... */ },
330/// };
331/// #
332/// # let query = GetUserQuery { user_id: 1 };
333/// # let result = query_bus.dispatch(query).await;
334/// # match result {
335/// # Ok(name) => println!("User name: {}", name),
336/// # Err(err) => eprintln!("Failed to get user: {:?}", err),
337/// # }
338/// # });
339/// ```
340///
341/// This assumes that the types of the handlers can be inferred automatically.
342///
343/// 2. **Providing type-handler pairs:**
344///
345/// ```
346/// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
347/// # rt.block_on(async {
348/// # use discern::query::Query;
349/// # use discern::async_trait;
350/// # use discern::query::QueryHandler;
351/// #
352/// # #[derive(Debug)]
353/// # struct GetUserQuery {
354/// # user_id: u64,
355/// # }
356/// #
357/// # impl Query for GetUserQuery {
358/// # type Output = String;
359/// # type Error = std::io::Error;
360/// # }
361/// #
362/// # struct GetUserQueryHandler;
363/// #
364/// # #[async_trait]
365/// # impl QueryHandler<GetUserQuery> for GetUserQueryHandler {
366/// # async fn handle(&self, query: GetUserQuery) -> Result<String, std::io::Error> {
367/// # Ok("Alice".to_string())
368/// # }
369/// # }
370/// use discern::query_bus;
371///
372/// let query_bus = query_bus! {
373/// GetUserQuery => GetUserQueryHandler { /* ... */ },
374/// };
375/// #
376/// # let query = GetUserQuery { user_id: 1 };
377/// # let result = query_bus.dispatch(query).await;
378/// # match result {
379/// # Ok(name) => println!("User name: {}", name),
380/// # Err(err) => eprintln!("Failed to get user: {:?}", err),
381/// # }
382/// # });
383/// ```
384///
385/// This explicitly specifies the query type associated with each handler.
386///
387/// # See Also
388///
389/// - [QueryBus](crate::query::QueryBus)
390#[macro_export]
391macro_rules! query_bus {
392 () => {{
393 $crate::query::QueryBus::new($crate::registry::QueryHandlerRegistry::new())
394 }};
395 ($($handler:expr),*$(,)?) => {{
396 let mut query_handler_registry = $crate::registry::QueryHandlerRegistry::new();
397 $(query_handler_registry.register($handler);)*
398 $crate::query::QueryBus::new(query_handler_registry)
399 }};
400 ($($query:ty => $handler:expr),*$(,)?) => {{
401 let mut query_handler_registry = $crate::registry::QueryHandlerRegistry::new();
402 $(query_handler_registry.register::<$query>($handler);)*
403 $crate::query::QueryBus::new(query_handler_registry)
404 }};
405 }
406
407/// A macro for creating a `QueryHandlerRegistry` instance.
408///
409/// This macro provides a convenient way to initialize a `QueryHandlerRegistry` and register multiple
410/// query handlers at once.
411///
412/// # Usage
413///
414/// You can use this macro in two ways:
415///
416/// 1. **Providing only handlers:**
417///
418/// ```
419/// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
420/// # rt.block_on(async {
421/// # use discern::query::Query;
422/// # use discern::async_trait;
423/// # use discern::query::QueryHandler;
424/// #
425/// # #[derive(Debug)]
426/// # struct GetUserQuery {
427/// # user_id: u64,
428/// # }
429/// #
430/// # impl Query for GetUserQuery {
431/// # type Output = String;
432/// # type Error = std::io::Error;
433/// # }
434/// #
435/// # struct GetUserQueryHandler;
436/// #
437/// # #[async_trait]
438/// # impl QueryHandler<GetUserQuery> for GetUserQueryHandler {
439/// # async fn handle(&self, query: GetUserQuery) -> Result<String, std::io::Error> {
440/// # Ok("Alice".to_string())
441/// # }
442/// # }
443/// use discern::query_registry;
444///
445/// let query_registry = query_registry! {
446/// GetUserQueryHandler { /* ... */ },
447/// };
448/// # });
449/// ```
450///
451/// This assumes that the types of the handlers can be inferred automatically.
452///
453/// 2. **Providing type-handler pairs:**
454///
455/// ```
456/// # let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
457/// # rt.block_on(async {
458/// # use discern::query::Query;
459/// # use discern::async_trait;
460/// # use discern::query::QueryHandler;
461/// #
462/// # #[derive(Debug)]
463/// # struct GetUserQuery {
464/// # user_id: u64,
465/// # }
466/// #
467/// # impl Query for GetUserQuery {
468/// # type Output = String;
469/// # type Error = std::io::Error;
470/// # }
471/// #
472/// # struct GetUserQueryHandler;
473/// #
474/// # #[async_trait]
475/// # impl QueryHandler<GetUserQuery> for GetUserQueryHandler {
476/// # async fn handle(&self, query: GetUserQuery) -> Result<String, std::io::Error> {
477/// # Ok("Alice".to_string())
478/// # }
479/// # }
480/// use discern::query_registry;
481///
482/// let query_registry = query_registry! {
483/// GetUserQuery => GetUserQueryHandler { /* ... */ },
484/// };
485/// # });
486/// ```
487///
488/// This explicitly specifies the query type associated with each handler.
489///
490/// # See Also
491///
492/// - [QueryHandlerRegistry](crate::registry::QueryHandlerRegistry)
493#[macro_export]
494macro_rules! query_registry {
495 () => {{
496 $crate::query::QueryHandlerRegistry::new()
497 }};
498 ($($handler:expr),*$(,)?) => {{
499 let mut query_handler_registry = $crate::registry::QueryHandlerRegistry::new();
500 $(query_handler_registry.register($handler);)*
501 query_handler_registry
502 }};
503 ($($query:ty => $handler:expr),*$(,)?) => {{
504 let mut query_handler_registry = $crate::registry::QueryHandlerRegistry::new();
505 $(query_handler_registry.register::<$query>($handler);)*
506 query_handler_registry
507 }};
508 }