1use std::any::{Any, TypeId};
4use std::collections::HashMap;
5use std::sync::{Arc, Mutex};
6
7pub trait Event: Send + Sync + 'static {
9 fn name(&self) -> &'static str;
10}
11
12type DynListener = Arc<dyn Fn(&dyn Any) + Send + Sync>;
13
14#[derive(Clone, Default)]
16pub struct EventBus {
17 inner: Arc<Mutex<HashMap<TypeId, Vec<DynListener>>>>,
18}
19
20impl EventBus {
21 pub fn new() -> Self {
22 Self::default()
23 }
24
25 pub fn listen<E, F>(&self, f: F)
27 where
28 E: Event,
29 F: Fn(&E) + Send + Sync + 'static,
30 {
31 let mut map = self.inner.lock().expect("EventBus");
32 map.entry(TypeId::of::<E>())
33 .or_default()
34 .push(Arc::new(move |any| {
35 if let Some(e) = any.downcast_ref::<E>() {
36 f(e);
37 }
38 }));
39 }
40
41 pub fn dispatch<E: Event>(&self, event: E) {
43 let listeners = {
44 let map = self.inner.lock().expect("EventBus");
45 map.get(&TypeId::of::<E>()).cloned().unwrap_or_default()
46 };
47 for listener in &listeners {
48 listener(&event);
49 }
50 }
51
52 pub fn listener_count<E: Event>(&self) -> usize {
54 self.inner
55 .lock()
56 .expect("EventBus")
57 .get(&TypeId::of::<E>())
58 .map(|v| v.len())
59 .unwrap_or(0)
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use std::sync::atomic::{AtomicUsize, Ordering};
67
68 struct Ping;
69 impl Event for Ping {
70 fn name(&self) -> &'static str {
71 "ping"
72 }
73 }
74
75 #[test]
76 fn order_and_multiple() {
77 let bus = EventBus::new();
78 let log = Arc::new(Mutex::new(Vec::new()));
79 let a = Arc::clone(&log);
80 let b = Arc::clone(&log);
81 bus.listen::<Ping, _>(move |_| a.lock().unwrap().push(1));
82 bus.listen::<Ping, _>(move |_| b.lock().unwrap().push(2));
83 assert_eq!(bus.listener_count::<Ping>(), 2);
84 bus.dispatch(Ping);
85 assert_eq!(*log.lock().unwrap(), vec![1, 2]);
86 }
87
88 #[test]
89 fn no_listeners_ok() {
90 let bus = EventBus::new();
91 let n = AtomicUsize::new(0);
92 bus.dispatch(Ping);
93 assert_eq!(n.load(Ordering::SeqCst), 0);
94 }
95}