eventear/
listener_container.rs1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::marker::PhantomData;
4
5use super::listener::{Listener, ListenerResult, OnEventError};
6
7pub type ListenerResults = Result<(), Vec<OnEventError>>;
8
9pub struct ListenerContainer<S: 'static> {
10 map: HashMap<TypeId, Box<dyn Any>>,
11 marker: PhantomData<S>,
12}
13
14type ListenerList<E, S> = Vec<Box<dyn Listener<E, S>>>;
15
16impl<S: 'static> ListenerContainer<S> {
17 pub fn new() -> Self {
18 ListenerContainer {
19 map: HashMap::new(),
20 marker: PhantomData,
21 }
22 }
23
24 fn get_listener_list<E: 'static>(&self) -> Option<&ListenerList<E, S>> {
25 self.map
26 .get(&TypeId::of::<E>())
27 .and_then(|boxed| boxed.downcast_ref::<ListenerList<E, S>>())
28 }
29
30 fn get_mut_listener_list<E: 'static>(&mut self) -> Option<&mut ListenerList<E, S>> {
31 self.map
32 .get_mut(&TypeId::of::<E>())
33 .and_then(|boxed| boxed.downcast_mut::<ListenerList<E, S>>())
34 }
35
36 pub fn register_listener_box<E: 'static>(&mut self, listener: Box<dyn Listener<E, S>>) {
37 match self.get_mut_listener_list() {
38 None => {
39 let mut list = Vec::new();
40 list.push(listener);
41 self.map.insert(TypeId::of::<E>(), Box::new(list));
42 }
43 Some(list) => {
44 list.push(listener);
45 }
46 }
47 }
48
49 pub fn register_listener<E: 'static, L: Listener<E, S> + 'static>(&mut self, listener: L) {
50 self.register_listener_box(Box::new(listener))
51 }
52
53 pub fn on_event<E: 'static>(&self, event: &E, state: &mut S) -> Result<(), Vec<OnEventError>> {
54 if let Some(list) = self.get_listener_list() {
55 list.iter()
56 .map(|listener| listener.on_event(event, state))
57 .fold(Ok(()), accumulate_errors)
58 } else {
59 Ok(())
60 }
61 }
62}
63
64pub fn accumulate_errors(
65 acc: ListenerResults,
66 result: ListenerResult,
67) -> Result<(), Vec<OnEventError>> {
68 if let Err(error) = result {
69 match acc {
70 Ok(()) => Err(vec![error]),
71 Err(mut error_list) => {
72 error_list.push(error);
73 Err(error_list)
74 }
75 }
76 } else {
77 acc
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_listener_container() {
87 struct SubState(u32, u32);
89 struct State(u32, SubState);
90 struct Increment;
91 let mut container = ListenerContainer::<State>::new();
93 container.register_listener(|_: &Increment, state: &mut State| {
95 state.0 += 1;
96 Ok(())
97 });
98 container.register_listener(|_: &Increment, state: &mut State| {
99 (state.1).0 += 1;
100 (state.1).1 += 1;
101 Ok(())
102 });
103 let event = Increment;
105 let mut state = State(0, SubState(0, 0));
106
107 container.on_event(&event, &mut state).unwrap();
109
110 assert_eq!(state.0, 1);
112 assert_eq!((state.1).0, 1);
113 assert_eq!((state.1).1, 1);
114 }
115}