basic functionality

master v0.1.0
brnrs 5 years ago
parent ce30e674b8
commit 8c720a77c7
  1. 9
      src/lib.rs
  2. 41
      src/listener.rs
  3. 115
      src/listener_container.rs

@ -1,7 +1,2 @@
#[cfg(test)] pub mod listener;
mod tests { pub mod listener_container;
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

@ -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…
Cancel
Save