use futures::future::{BoxFuture, FutureExt};
use std::any::Any;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
pub type EventCallback<D> = Arc<dyn (Fn(D) -> BoxFuture<'static, ()>) + Send + Sync>;
pub trait Event<D>
where
D: Clone + Send + Sync + 'static,
{
fn map(&self) -> Arc<RwLock<HashMap<String, Vec<Box<dyn Any + Send + Sync>>>>>;
fn _on(&self, event_name: String, callback: EventCallback<D>) -> impl Future<Output = ()> {
async {
let handlers = self.map();
let mut map = handlers.write().await;
let list = map.entry(event_name).or_insert_with(Vec::new);
let cb: EventCallback<D> = callback;
list.push(Box::new(cb));
}
}
fn notify(&self, event_name: String, data: D) -> BoxFuture<'static, ()> {
let handlers_lock = self.map();
let data = data.clone();
(async move {
let map = handlers_lock.read().await;
if let Some(any_callbacks) = map.get(&event_name) {
for any_cb in any_callbacks {
if let Some(cb) = any_cb.downcast_ref::<EventCallback<D>>() {
let d = data.clone();
let cb_clone = Arc::clone(cb);
tokio::spawn(async move {
cb_clone(d).await;
});
}
}
}
})
.boxed()
}
}
pub struct EventEmitter {
handlers: Arc<RwLock<HashMap<String, Vec<Box<dyn Any + Send + Sync>>>>>,
}
impl Default for EventEmitter {
fn default() -> Self {
Self::new()
}
}
impl EventEmitter {
pub fn new() -> Self {
Self {
handlers: Arc::new(RwLock::new(HashMap::new())),
}
}
pub async fn on<D>(&self, name: String, cb: EventCallback<D>)
where
D: Clone + Send + Sync + 'static,
{
Event::<D>::_on(self, name, cb).await;
}
}
impl<D> Event<D> for EventEmitter
where
D: Clone + Send + Sync + 'static,
{
fn map(&self) -> Arc<RwLock<HashMap<String, Vec<Box<dyn Any + Send + Sync>>>>> {
Arc::clone(&self.handlers)
}
}