use crate::{EventStream, Sender};
use std::{
any::{Any, TypeId},
collections::{BTreeSet, HashMap},
marker::PhantomData,
};
type SenderList = Vec<(Id, Box<dyn Any>)>;
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Id(usize);
#[derive(Default)]
pub struct EventMap {
inner: HashMap<TypeId, SenderList>,
id: usize,
}
impl EventMap {
pub fn new() -> Self {
Self::default()
}
pub fn register<T: Clone + 'static>(&mut self) -> EventStream<T> {
let (tx, rx) = crate::channel::unbounded();
self.inner
.entry(TypeId::of::<T>())
.or_default()
.push((Id(self.id), Box::new(tx)));
self.id += 1;
EventStream { inner: rx }
}
pub fn send<T: Clone + 'static>(&mut self, msg: T) -> bool {
if self.active::<T>() == 0 {
return false;
}
let handlers = match self.get_senders::<T>() {
Some(handlers) => handlers,
None => return false,
};
let mut bad = BTreeSet::new();
for (id, handler) in handlers {
if let Err(..) = handler.send(msg.clone()) {
bad.insert(id);
}
}
self.remove::<T>(bad);
true
}
pub fn active<T: 'static>(&self) -> usize {
self.inner
.get(&TypeId::of::<T>())
.map(Vec::len)
.unwrap_or_default()
}
pub fn is_empty<T: 'static>(&self) -> bool {
self.active::<T>() == 0
}
pub fn get_senders<T: 'static>(&self) -> Option<Senders<'_, T>> {
self.inner.get(&TypeId::of::<T>()).map(|list| Senders {
inner: list.iter(),
marker: PhantomData,
})
}
pub fn reset(&mut self) {
std::mem::take(&mut self.inner);
self.id = 0;
}
pub(crate) fn remove<T: 'static>(&mut self, mut values: BTreeSet<Id>) {
if values.is_empty() {
return;
}
if let Some(inner) = self.inner.get_mut(&TypeId::of::<T>()) {
inner.retain(|(id, _)| !values.remove(&id))
}
}
}
pub struct Senders<'a, T: 'static> {
inner: std::slice::Iter<'a, (Id, Box<dyn Any>)>,
marker: PhantomData<T>,
}
impl<'a, T: 'static> Iterator for Senders<'a, T> {
type Item = (Id, Sender<T>);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().and_then(|(id, d)| {
let sender = d.downcast_ref::<Sender<T>>().cloned()?;
Some((*id, sender))
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn event_map() {
#[derive(Clone, Debug, PartialEq)]
struct Message {
data: String,
}
let mut map = EventMap::new();
assert_eq!(map.is_empty::<i32>(), true);
assert_eq!(map.is_empty::<String>(), true);
assert_eq!(map.is_empty::<Message>(), true);
assert_eq!(map.active::<i32>(), 0);
let mut i1 = map.register::<i32>();
let mut i2 = map.register::<i32>();
assert_eq!(map.active::<i32>(), 2);
assert_eq!(map.active::<Message>(), 0);
let mut m1 = map.register::<Message>();
let mut m2 = map.register::<Message>();
assert_eq!(map.active::<Message>(), 2);
assert_eq!(map.send(42_i32), true);
let msg = Message {
data: String::from("hello world"),
};
assert_eq!(map.send(msg.clone()), true);
assert_eq!(i1.next().unwrap(), 42);
assert_eq!(i2.next().unwrap(), 42);
assert_eq!(m1.next().unwrap(), msg);
assert_eq!(m2.next().unwrap(), msg);
assert_eq!(map.send(()), false);
drop(i1);
assert_eq!(map.send(43_i32), true);
assert_eq!(i2.next().unwrap(), 43);
assert_eq!(map.active::<i32>(), 1);
}
}