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>()).or_default().push(Arc::new(move |any| {
33 if let Some(e) = any.downcast_ref::<E>() {
34 f(e);
35 }
36 }));
37 }
38
39 pub fn dispatch<E: Event>(&self, event: E) {
41 let listeners = {
42 let map = self.inner.lock().expect("EventBus");
43 map.get(&TypeId::of::<E>()).cloned().unwrap_or_default()
44 };
45 for listener in &listeners {
46 listener(&event);
47 }
48 }
49
50 pub fn listener_count<E: Event>(&self) -> usize {
52 self.inner
53 .lock()
54 .expect("EventBus")
55 .get(&TypeId::of::<E>())
56 .map(|v| v.len())
57 .unwrap_or(0)
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use std::sync::atomic::{AtomicUsize, Ordering};
65
66 struct Ping;
67 impl Event for Ping {
68 fn name(&self) -> &'static str {
69 "ping"
70 }
71 }
72
73 #[test]
74 fn order_and_multiple() {
75 let bus = EventBus::new();
76 let log = Arc::new(Mutex::new(Vec::new()));
77 let a = Arc::clone(&log);
78 let b = Arc::clone(&log);
79 bus.listen::<Ping, _>(move |_| a.lock().unwrap().push(1));
80 bus.listen::<Ping, _>(move |_| b.lock().unwrap().push(2));
81 assert_eq!(bus.listener_count::<Ping>(), 2);
82 bus.dispatch(Ping);
83 assert_eq!(*log.lock().unwrap(), vec![1, 2]);
84 }
85
86 #[test]
87 fn no_listeners_ok() {
88 let bus = EventBus::new();
89 let n = AtomicUsize::new(0);
90 bus.dispatch(Ping);
91 assert_eq!(n.load(Ordering::SeqCst), 0);
92 }
93}