Skip to main content

eventear/
listener_container.rs

1use 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        // Given structs
88        struct SubState(u32, u32);
89        struct State(u32, SubState);
90        struct Increment;
91        // And listener container
92        let mut container = ListenerContainer::<State>::new();
93        // And listeners
94        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        // And values
104        let event = Increment;
105        let mut state = State(0, SubState(0, 0));
106
107        // When
108        container.on_event(&event, &mut state).unwrap();
109
110        // Then
111        assert_eq!(state.0, 1);
112        assert_eq!((state.1).0, 1);
113        assert_eq!((state.1).1, 1);
114    }
115}