parent
ce30e674b8
commit
8c720a77c7
@ -1,7 +1,2 @@ |
||||
#[cfg(test)] |
||||
mod tests { |
||||
#[test] |
||||
fn it_works() { |
||||
assert_eq!(2 + 2, 4); |
||||
} |
||||
} |
||||
pub mod listener; |
||||
pub mod listener_container; |
@ -0,0 +1,41 @@ |
||||
#[derive(Debug)] |
||||
pub struct OnEventError(String); |
||||
|
||||
pub type ListenerResult = Result<(), OnEventError>; |
||||
|
||||
pub trait Listener<E: 'static, S: 'static> { |
||||
fn on_event(&self, event: &E, state: &mut S) -> ListenerResult; |
||||
} |
||||
|
||||
impl<E: 'static, S: 'static, F: Fn(&E, &mut S) -> ListenerResult> Listener<E, S> for F { |
||||
fn on_event(&self, event: &E, state: &mut S) -> ListenerResult { |
||||
self(event, state) |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn test_closure_as_listener() { |
||||
// Given structs
|
||||
struct State(u32); |
||||
struct Increment; |
||||
// And closure as Listener
|
||||
let listener = |_: &Increment, state: &mut State| { |
||||
state.0 += 1; |
||||
Ok(()) |
||||
}; |
||||
// And values
|
||||
let event = Increment; |
||||
let mut state = State(0); |
||||
|
||||
// When
|
||||
listener.on_event(&event, &mut state).unwrap(); |
||||
|
||||
// Then
|
||||
assert_eq!(state.0, 1); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,115 @@ |
||||
use std::any::{Any, TypeId}; |
||||
use std::collections::HashMap; |
||||
use std::marker::PhantomData; |
||||
|
||||
use super::listener::{Listener, ListenerResult, OnEventError}; |
||||
|
||||
pub type ListenerResults = Result<(), Vec<OnEventError>>; |
||||
|
||||
pub struct ListenerContainer<S: 'static> { |
||||
map: HashMap<TypeId, Box<dyn Any>>, |
||||
marker: PhantomData<S>, |
||||
} |
||||
|
||||
type ListenerList<E, S> = Vec<Box<dyn Listener<E, S>>>; |
||||
|
||||
impl<S: 'static> ListenerContainer<S> { |
||||
pub fn new() -> Self { |
||||
ListenerContainer { |
||||
map: HashMap::new(), |
||||
marker: PhantomData, |
||||
} |
||||
} |
||||
|
||||
fn get_listener_list<E: 'static>(&self) -> Option<&ListenerList<E, S>> { |
||||
self.map |
||||
.get(&TypeId::of::<E>()) |
||||
.and_then(|boxed| boxed.downcast_ref::<ListenerList<E, S>>()) |
||||
} |
||||
|
||||
fn get_mut_listener_list<E: 'static>(&mut self) -> Option<&mut ListenerList<E, S>> { |
||||
self.map |
||||
.get_mut(&TypeId::of::<E>()) |
||||
.and_then(|boxed| boxed.downcast_mut::<ListenerList<E, S>>()) |
||||
} |
||||
|
||||
pub fn register_listener_box<E: 'static>(&mut self, listener: Box<dyn Listener<E, S>>) { |
||||
match self.get_mut_listener_list() { |
||||
None => { |
||||
let mut list = Vec::new(); |
||||
list.push(listener); |
||||
self.map.insert(TypeId::of::<E>(), Box::new(list)); |
||||
} |
||||
Some(list) => { |
||||
list.push(listener); |
||||
} |
||||
} |
||||
} |
||||
|
||||
pub fn register_listener<E: 'static, L: Listener<E, S> + 'static>(&mut self, listener: L) { |
||||
self.register_listener_box(Box::new(listener)) |
||||
} |
||||
|
||||
pub fn on_event<E: 'static>(&self, event: &E, state: &mut S) -> Result<(), Vec<OnEventError>> { |
||||
if let Some(list) = self.get_listener_list() { |
||||
list.iter() |
||||
.map(|listener| listener.on_event(event, state)) |
||||
.fold(Ok(()), accumulate_errors) |
||||
} else { |
||||
Ok(()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
pub fn accumulate_errors( |
||||
acc: ListenerResults, |
||||
result: ListenerResult, |
||||
) -> Result<(), Vec<OnEventError>> { |
||||
if let Err(error) = result { |
||||
match acc { |
||||
Ok(()) => Err(vec![error]), |
||||
Err(mut error_list) => { |
||||
error_list.push(error); |
||||
Err(error_list) |
||||
} |
||||
} |
||||
} else { |
||||
acc |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn test_listener_container() { |
||||
// Given structs
|
||||
struct SubState(u32, u32); |
||||
struct State(u32, SubState); |
||||
struct Increment; |
||||
// And listener container
|
||||
let mut container = ListenerContainer::<State>::new(); |
||||
// And listeners
|
||||
container.register_listener(|_: &Increment, state: &mut State| { |
||||
state.0 += 1; |
||||
Ok(()) |
||||
}); |
||||
container.register_listener(|_: &Increment, state: &mut State| { |
||||
(state.1).0 += 1; |
||||
(state.1).1 += 1; |
||||
Ok(()) |
||||
}); |
||||
// And values
|
||||
let event = Increment; |
||||
let mut state = State(0, SubState(0, 0)); |
||||
|
||||
// When
|
||||
container.on_event(&event, &mut state).unwrap(); |
||||
|
||||
// Then
|
||||
assert_eq!(state.0, 1); |
||||
assert_eq!((state.1).0, 1); |
||||
assert_eq!((state.1).1, 1); |
||||
} |
||||
} |
Loading…
Reference in new issue