use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use core::any::{Any, TypeId};
use crate::ecs::event::Events;
trait AnyEventQueue: Send {
fn update(&mut self);
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<E: Send + 'static> AnyEventQueue for Events<E> {
fn update(&mut self) {
Events::update(self);
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[derive(Default)]
pub struct EventStore {
queues: BTreeMap<TypeId, Box<dyn AnyEventQueue>>,
}
impl EventStore {
pub fn new() -> EventStore {
EventStore::default()
}
pub fn get<E: 'static>(&self) -> Option<&Events<E>> {
self.queues
.get(&TypeId::of::<E>())
.and_then(|queue| queue.as_any().downcast_ref::<Events<E>>())
}
pub fn get_mut_or_create<E: Send + 'static>(&mut self) -> &mut Events<E> {
self.queues
.entry(TypeId::of::<E>())
.or_insert_with(|| Box::new(Events::<E>::new()))
.as_any_mut()
.downcast_mut::<Events<E>>()
.expect("queue stored under E's TypeId is Events<E>")
}
pub fn update_all(&mut self) {
for queue in self.queues.values_mut() {
queue.update();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_before_first_write_is_none() {
let store = EventStore::new();
assert!(store.get::<u32>().is_none());
}
#[test]
fn queue_persists_across_accesses() {
let mut store = EventStore::new();
store.get_mut_or_create::<u32>().send(7);
assert_eq!(store.get::<u32>().unwrap().len(), 1);
assert_eq!(store.get_mut_or_create::<u32>().len(), 1);
}
#[test]
fn update_all_rotates_every_queue() {
let mut store = EventStore::new();
store.get_mut_or_create::<u32>().send(1);
store.get_mut_or_create::<&str>().send("a");
store.update_all();
assert_eq!(store.get::<u32>().unwrap().len(), 1);
assert_eq!(store.get::<&str>().unwrap().len(), 1);
store.update_all();
assert!(store.get::<u32>().unwrap().is_empty());
assert!(store.get::<&str>().unwrap().is_empty());
}
}