use std::{
any::Any,
cell::{Ref, RefCell},
};
type Callback = Box<dyn Fn(&dyn Any)>;
#[derive(Default)]
pub struct Signal {
listeners: RefCell<Vec<Callback>>,
last_value: RefCell<Option<Box<dyn Any>>>,
}
impl Signal {
pub fn new() -> Self {
Signal {
listeners: RefCell::new(Vec::new()),
last_value: RefCell::new(None),
}
}
pub fn connect<F>(&self, callback: F)
where
F: Fn(&dyn Any) + 'static,
{
if let Some(value) = &*self.last_value.borrow() {
callback(&**value);
}
self.listeners.borrow_mut().push(Box::new(callback));
}
pub fn emit<T: Any + Clone>(&self, value: &T) {
let cloned = (*value).clone();
*self.last_value.borrow_mut() = Some(Box::new(cloned));
for callback in &*self.listeners.borrow_mut() {
callback(value);
}
}
pub fn emit_unclonable<T: Any>(&self, value: &T) {
for callback in &*self.listeners.borrow_mut() {
callback(value);
}
}
pub fn last_value_ref(&self) -> Ref<'_, Option<Box<dyn Any>>> {
self.last_value.borrow()
}
pub fn with_last_value<F, R>(&self, f: F) -> R
where
F: FnOnce(Option<&dyn Any>) -> R,
{
let last_value = self.last_value_ref();
let any_ref = last_value.as_ref().map(|boxed| &**boxed as &dyn Any);
f(any_ref)
}
pub fn get_last_value_cloned<T: Any + Clone>(&self) -> Option<T> {
self.with_last_value(|opt| opt.and_then(|any| any.downcast_ref::<T>().cloned()))
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum SignalNames {
Keyboard,
Custom(String),
}