1#![forbid(unsafe_code)]
4
5use as_any::{AsAny, Downcast};
6use std::any::{Any, TypeId};
7use std::collections::HashMap;
8
9pub trait Event: AsAny {}
10
11type OneOneED<E> = Box<dyn FnMut(&E) + 'static>;
12type OneEventDispatcher<E> = Vec<OneOneED<E>>;
13
14pub struct EventDispatcher(HashMap<TypeId, (fn(&mut dyn Any, &dyn Event), Box<dyn Any>)>);
15
16fn dyn_delegate<E: Event>(listeners: &mut dyn Any, event: &dyn Event) {
17 let listeners = listeners
18 .downcast_mut::<OneEventDispatcher<E>>()
19 .expect("dyn_delegate: mismatching listeners type");
20 let event: &E = event
21 .downcast_ref()
22 .expect("dyn_delegate: mismatching event type");
23
24 for callback in listeners {
25 callback(event);
26 }
27}
28
29impl EventDispatcher {
30 #[inline]
31 pub fn new() -> EventDispatcher {
32 EventDispatcher(HashMap::new())
33 }
34
35 pub fn add_event_listener<E, F>(&mut self, f: F)
36 where
37 E: Event,
38 F: FnMut(&E) + 'static,
39 {
40 (*self
41 .0
42 .entry(TypeId::of::<E>())
43 .or_insert_with(|| (dyn_delegate::<E>, Box::new(Vec::<OneOneED<E>>::new())))
44 .1)
45 .downcast_mut::<OneEventDispatcher<E>>()
46 .unwrap()
47 .push(Box::new(f));
48 }
49
50 #[inline]
51 pub fn clear<E: Event>(&mut self) {
52 self.0.remove(&TypeId::of::<E>());
53 }
54
55 #[inline]
56 pub fn clear_all(&mut self) {
57 self.0.clear();
58 }
59
60 pub fn trigger<E: Event>(&mut self, event: &E) {
61 if let Some(listeners) = self.0.get_mut(&TypeId::of::<E>()) {
62 for callback in (*listeners.1).downcast_mut::<OneEventDispatcher<E>>().unwrap() {
63 callback(event);
64 }
65 }
66 }
67
68 pub fn trigger_dyn(&mut self, event: &dyn Event) {
69 if let Some(listeners) = self.0.get_mut(&event.type_id()) {
70 let d2 = listeners.0;
71 d2(&mut *listeners.1, event);
72 }
73 }
74}
75
76#[cfg(test)]
77mod test {
78 use super::*;
79 use std::{cell::RefCell, rc::Rc};
80
81 struct OnClick {
82 mouse_x: i32,
83 mouse_y: i32,
84 }
85
86 impl Event for OnClick {}
87
88 #[test]
89 fn basic() {
90 let mut node = EventDispatcher::new();
91 let x = Rc::new(RefCell::new(0));
92 let x2 = Rc::clone(&x);
93 node.add_event_listener(move |event: &OnClick| {
94 *x2.borrow_mut() += 1;
95 assert_eq!(event.mouse_x, 10);
96 assert_eq!(event.mouse_y, 5);
97 });
98 let e = OnClick {
99 mouse_x: 10,
100 mouse_y: 5,
101 };
102 node.trigger(&e);
103 node.trigger_dyn(&e);
104 assert_eq!(*x.borrow(), 2);
105 }
106}