use crate::sub::{self, AnySubscriber, Subscription};
use std::any::Any;
use std::sync::{Arc, RwLock};
#[derive(Debug, Default)]
pub struct EventBus {
registry: RwLock<Vec<Box<dyn AnySubscriber>>>,
}
impl EventBus {
pub const fn new() -> Self {
let registry = RwLock::new(Vec::new());
Self { registry }
}
pub fn publish<T>(&self, event: T) -> usize
where
T: Send + Clone + 'static,
{
let registry = self.registry.read().expect("failed to lock registry");
registry.iter().fold(0, |count, subscriber| {
#[allow(clippy::arithmetic_side_effects, reason = "Can never overflow")]
(count + subscriber.send(&event) as usize)
})
}
#[must_use]
pub fn subscribe<T>(&self, backlog: usize) -> Subscription<T>
where
T: Send + Clone + 'static,
{
fn filter_map<T>(event: &dyn Any) -> Option<T>
where
T: Clone + 'static,
{
event.downcast_ref::<T>().cloned()
}
self.subscribe_where(backlog, filter_map)
}
#[must_use]
pub fn subscribe_where<T, F>(&self, backlog: usize, filter_map: F) -> Subscription<T>
where
T: Send + Clone + 'static,
F: Fn(&dyn Any) -> Option<T> + Send + Sync + 'static,
{
let convert = Arc::new(filter_map);
let (subscriber, subscription) = sub::pair(backlog, convert);
let subscriber: Box<dyn AnySubscriber> = Box::new(subscriber);
let mut registry = self.registry.write().expect("failed to lock registry");
registry.push(subscriber);
subscription
}
pub fn shrink_to_fit(&self) {
let mut registry = self.registry.write().expect("failed to lock registry");
registry.retain(|subscriber| subscriber.is_alive());
registry.shrink_to_fit();
}
}