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