use std::cell::RefCell;
use std::rc::Rc;
use derivative::Derivative;
use futures::channel::oneshot::*;
use yew::prelude::*;
#[derive(Derivative)]
#[derivative(Default(bound = ""))]
pub struct PubSub<T: Clone> {
listeners: Rc<RefCell<Vec<Callback<T>>>>,
once_listeners: Rc<RefCell<Vec<Callback<T>>>>,
}
pub trait AddListener<T> {
fn add_listener(&self, f: T) -> Subscription;
}
impl<T: Clone + 'static> PubSub<T> {
pub fn emit_all(&self, val: T) {
let listeners = self.listeners.borrow().clone();
for listener in listeners.iter() {
listener.emit(val.clone());
}
for listener in self.once_listeners.replace(Vec::default()).into_iter() {
listener.emit(val.clone());
}
}
pub fn callback(&self) -> Callback<T> {
let listeners = self.listeners.clone();
Callback::from(move |val: T| {
let listeners = listeners.borrow().clone();
for listener in listeners.iter() {
listener.emit(val.clone());
}
})
}
pub fn add_listener_once<F: FnOnce(T) + 'static>(&self, f: F) {
let f = RefCell::new(Some(f));
let cb = Callback::from(move |x| f.borrow_mut().take().map(|f| f(x)).unwrap_or_default());
self.once_listeners.borrow_mut().insert(0, cb);
}
pub async fn listen_once(&self) -> Result<T, Canceled> {
let (sender, receiver) = channel::<T>();
self.add_listener_once(move |x| sender.send(x).unwrap_or(()));
receiver.await
}
}
impl<T: Clone + 'static> AddListener<Callback<T>> for PubSub<T> {
fn add_listener(&self, f: Callback<T>) -> Subscription {
let listeners = self.listeners.clone();
self.listeners.borrow_mut().insert(0, f.clone());
Subscription(Box::new(move || listeners.borrow_mut().retain(|x| *x != f)))
}
}
impl<T, U> AddListener<U> for PubSub<T>
where
T: Clone + 'static,
U: Fn(T) + 'static,
{
fn add_listener(&self, f: U) -> Subscription {
let f = Callback::from(f);
let listeners = self.listeners.clone();
listeners.borrow_mut().insert(0, f.clone());
Subscription(Box::new(move || listeners.borrow_mut().retain(|x| *x != f)))
}
}
#[must_use]
pub struct Subscription(Box<dyn Fn()>);
impl Drop for Subscription {
fn drop(&mut self) {
(*self.0)();
}
}