use std::sync::Arc;
use std::vec::IntoIter;
use std::future::Future;
use futures::future::join_all;
use tokio::task::{JoinError, JoinHandle};
use std::fmt::{Debug, Formatter};
type Callback<T, R = ()> = dyn Fn(Arc<T>)
-> JoinHandle<R> + Send + Sync + 'static;
pub struct Event<T, R = ()> {
pub callbacks: Vec<Arc<Callback<T, R>>>,
}
impl<T: Send + Sync + 'static, R: Send + 'static> Event<T, R> {
pub fn new() -> Self {
Event {
callbacks: Vec::new(),
}
}
pub fn connect<F, Fut>(&mut self, callback: F) -> usize
where
F: Fn(Arc<T>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = R> + Send + 'static
{
let arc_cb = Arc::new(callback);
let cb: Arc<Callback<T, R>> = Arc::new(move |data: Arc<T>| {
let c = Arc::clone(&arc_cb);
tokio::spawn(async move {
(c)(data).await
})
});
self.callbacks.push(cb);
self.callbacks.len() - 1
}
pub fn disconnect(&mut self, id: usize) -> Option<Arc<Callback<T, R>>> {
Some(self.callbacks.remove(id))
}
pub async fn fire(&self, data: T) -> Vec<Result<R, JoinError>> {
let arc_data = Arc::new(data);
let handles = self.callbacks
.iter()
.map(|cb|
cb(Arc::clone(&arc_data))
).collect::<Vec<_>>();
join_all(handles).await
}
}
impl<T, R> Debug for Event<T, R> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Event")
.field("connections", &self.callbacks.len())
.finish()
}
}
impl<T, R> Clone for Event<T, R> {
fn clone(&self) -> Self {
Event {
callbacks: self.callbacks.clone()
}
}
}
impl<T, R> IntoIterator for Event<T, R>
where
T: Send + 'static,
R: Send + 'static
{
type Item = Arc<Callback<T, R>>;
type IntoIter = IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.callbacks.into_iter()
}
}
impl<T: Send + Sync + 'static, R: Send + 'static> Default for Event<T, R> {
fn default() -> Self {
Self::new()
}
}