1use async_trait::async_trait;
4use dashmap::DashMap;
5use std::any::{Any, TypeId};
6use std::sync::Arc;
7use thiserror::Error;
8
9pub trait Command: Send + Sync + 'static {
13 type Result: Send;
15}
16
17#[async_trait]
19pub trait CommandHandler<C: Command>: Send + Sync {
20 async fn handle(&self, command: C) -> Result<C::Result, CommandError>;
22}
23
24#[derive(Debug, Error)]
26pub enum CommandError {
27 #[error("Command execution failed: {0}")]
28 ExecutionFailed(String),
29
30 #[error("Handler not found for command")]
31 HandlerNotFound,
32
33 #[error("Validation error: {0}")]
34 ValidationError(String),
35
36 #[error("Business rule violation: {0}")]
37 BusinessRuleViolation(String),
38}
39
40#[async_trait]
42trait DynCommandHandler: Send + Sync {
43 async fn handle_dyn(
44 &self,
45 command: Box<dyn Any + Send>,
46 ) -> Result<Box<dyn Any + Send>, CommandError>;
47}
48
49struct TypedCommandHandler<C: Command, H: CommandHandler<C>> {
51 handler: H,
52 _phantom: std::marker::PhantomData<C>,
53}
54
55impl<C: Command, H: CommandHandler<C>> TypedCommandHandler<C, H> {
56 fn new(handler: H) -> Self {
57 Self {
58 handler,
59 _phantom: std::marker::PhantomData,
60 }
61 }
62}
63
64#[async_trait]
65impl<C: Command, H: CommandHandler<C>> DynCommandHandler for TypedCommandHandler<C, H> {
66 async fn handle_dyn(
67 &self,
68 command: Box<dyn Any + Send>,
69 ) -> Result<Box<dyn Any + Send>, CommandError> {
70 match command.downcast::<C>() {
71 Ok(cmd) => {
72 let result = self.handler.handle(*cmd).await?;
73 Ok(Box::new(result))
74 }
75 Err(_) => Err(CommandError::ExecutionFailed("Type mismatch".to_string())),
76 }
77 }
78}
79
80pub struct CommandBus {
82 handlers: DashMap<TypeId, Arc<dyn DynCommandHandler>>,
83}
84
85impl CommandBus {
86 pub fn new() -> Self {
88 Self {
89 handlers: DashMap::new(),
90 }
91 }
92
93 pub fn register<C, H>(&self, handler: H)
95 where
96 C: Command,
97 H: CommandHandler<C> + 'static,
98 {
99 let type_id = TypeId::of::<C>();
100 let handler = Arc::new(TypedCommandHandler::new(handler));
101 self.handlers.insert(type_id, handler);
102 }
103
104 pub async fn execute<C>(&self, command: C) -> Result<C::Result, CommandError>
106 where
107 C: Command,
108 {
109 let type_id = TypeId::of::<C>();
110
111 let handler = self
112 .handlers
113 .get(&type_id)
114 .ok_or(CommandError::HandlerNotFound)?;
115
116 let boxed_command: Box<dyn Any + Send> = Box::new(command);
117 let result = handler.handle_dyn(boxed_command).await?;
118
119 match result.downcast::<C::Result>() {
120 Ok(result) => Ok(*result),
121 Err(_) => Err(CommandError::ExecutionFailed(
122 "Result type mismatch".to_string(),
123 )),
124 }
125 }
126}
127
128impl Default for CommandBus {
129 fn default() -> Self {
130 Self::new()
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 struct CreateUserCommand {
139 email: String,
140 }
141
142 impl Command for CreateUserCommand {
143 type Result = String; }
145
146 struct CreateUserHandler;
147
148 #[async_trait]
149 impl CommandHandler<CreateUserCommand> for CreateUserHandler {
150 async fn handle(&self, command: CreateUserCommand) -> Result<String, CommandError> {
151 Ok(format!("user-{}", command.email))
152 }
153 }
154
155 #[tokio::test]
156 async fn test_command_bus() {
157 let bus = CommandBus::new();
158 bus.register::<CreateUserCommand, _>(CreateUserHandler);
159
160 let command = CreateUserCommand {
161 email: "alice@example.com".to_string(),
162 };
163
164 let result = bus.execute(command).await.unwrap();
165 assert_eq!(result, "user-alice@example.com");
166 }
167}