orbit/events/
dispatcher.rs1use std::sync::{Arc, Mutex};
7
8use super::Event;
9
10pub trait Handler<E>: Send + Sync {
12 fn handle(&self, event: &E) -> Result<(), String>;
14}
15
16impl<E, F> Handler<E> for F
18where
19 F: Fn(&E) -> Result<(), String> + Send + Sync,
20{
21 fn handle(&self, event: &E) -> Result<(), String> {
22 self(event)
23 }
24}
25
26#[derive(Clone)]
28pub struct Dispatcher<E: Event> {
29 handlers: Arc<Mutex<Vec<Box<dyn Handler<E>>>>>,
31}
32
33impl<E: Event> Default for Dispatcher<E> {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl<E: Event> Dispatcher<E> {
40 pub fn new() -> Self {
42 Self {
43 handlers: Arc::new(Mutex::new(Vec::new())),
44 }
45 }
46
47 pub fn add_handler<H>(&mut self, handler: H) -> Result<(), String>
49 where
50 H: Handler<E> + 'static,
51 {
52 let mut handlers = self
53 .handlers
54 .lock()
55 .map_err(|e| format!("Failed to lock handlers: {e}"))?;
56
57 handlers.push(Box::new(handler));
58 Ok(())
59 }
60
61 pub fn on<F>(&mut self, f: F) -> Result<(), String>
63 where
64 F: Fn(&E) -> Result<(), String> + Send + Sync + 'static,
65 {
66 self.add_handler(f)
67 }
68
69 pub fn dispatch(&self, event: &E) -> Result<(), String> {
71 let handlers = self
72 .handlers
73 .lock()
74 .map_err(|e| format!("Failed to lock handlers: {e}"))?;
75
76 let mut errors = Vec::new();
77
78 for handler in handlers.iter() {
79 if let Err(e) = handler.handle(event) {
80 errors.push(e);
81 }
82 }
83
84 if errors.is_empty() {
85 Ok(())
86 } else {
87 Err(errors.join(", "))
88 }
89 }
90
91 pub fn clear(&mut self) -> Result<(), String> {
93 let mut handlers = self
94 .handlers
95 .lock()
96 .map_err(|e| format!("Failed to lock handlers: {e}"))?;
97
98 handlers.clear();
99 Ok(())
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use std::sync::atomic::{AtomicBool, Ordering};
107
108 #[derive(Clone)]
109 struct TestEvent {
110 data: String,
111 }
112
113 #[test]
116 fn test_dispatcher() {
117 let mut dispatcher = Dispatcher::<TestEvent>::new();
118 let called = Arc::new(AtomicBool::new(false));
119 let called_clone = called.clone();
120
121 dispatcher
122 .on(move |event: &TestEvent| {
123 called_clone.store(true, Ordering::SeqCst);
124 assert_eq!(event.data, "test");
125 Ok(())
126 })
127 .unwrap();
128
129 dispatcher
130 .dispatch(&TestEvent {
131 data: "test".to_string(),
132 })
133 .unwrap();
134
135 assert!(called.load(Ordering::SeqCst));
136 }
137}