1use std::collections::HashMap;
14use std::fmt;
15
16use crate::context::RuntimeContext;
17use crate::envelope::CommandEnvelope;
18use crate::error::{RuntimeError, RuntimeResult};
19use crate::handler::{CommandHandler, CommandResult};
20use crate::ids::CommandName;
21
22#[derive(Default)]
24pub struct CommandBus {
25 handlers: HashMap<CommandName, Box<dyn CommandHandler + Send + Sync>>,
26}
27
28impl fmt::Debug for CommandBus {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.debug_struct("CommandBus")
31 .field("handler_count", &self.handlers.len())
32 .finish()
33 }
34}
35
36impl CommandBus {
37 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn register_handler<H: CommandHandler + 'static>(
44 &mut self,
45 handler: H,
46 ) -> RuntimeResult<()> {
47 let name = handler.command_name();
48 if self.handlers.contains_key(&name) {
49 return Err(RuntimeError::HandlerAlreadyRegistered(name));
50 }
51
52 self.handlers.insert(name, Box::new(handler));
53 Ok(())
54 }
55
56 pub fn contains_handler(&self, name: &CommandName) -> bool {
58 self.handlers.contains_key(name)
59 }
60
61 pub fn len(&self) -> usize {
63 self.handlers.len()
64 }
65
66 pub fn is_empty(&self) -> bool {
68 self.handlers.is_empty()
69 }
70
71 pub fn dispatch(
73 &self,
74 command: &CommandEnvelope,
75 context: &dyn RuntimeContext,
76 ) -> RuntimeResult<CommandResult> {
77 let name = command.command_name();
78 let Some(handler) = self.handlers.get(name) else {
79 return Err(RuntimeError::HandlerNotFound(name.clone()));
80 };
81
82 handler.handle(command, context)
83 }
84}
85
86#[cfg(test)]
87#[path = "bus_tests.rs"]
88mod tests;