2024-03-11 18:29:26 -05:00
|
|
|
use std::any::{Any, TypeId};
|
|
|
|
use hashbrown::HashMap;
|
|
|
|
use nohash_hasher::BuildNoHashHasher;
|
|
|
|
|
|
|
|
/// A marker trait for signals
|
|
|
|
pub trait UiSignal: Any {}
|
|
|
|
|
2024-03-11 19:26:48 -05:00
|
|
|
// #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
|
|
|
|
// pub(crate) struct DummySignal;
|
|
|
|
// impl UiSignal for DummySignal {}
|
2024-03-11 18:29:26 -05:00
|
|
|
|
2024-03-11 19:26:48 -05:00
|
|
|
pub struct SignalStore {
|
2024-03-11 18:29:26 -05:00
|
|
|
///XXX: is this truly the most efficient structure?
|
|
|
|
sig: HashMap<TypeId, Vec<Box<dyn Any>>, BuildNoHashHasher<u64>>
|
|
|
|
}
|
|
|
|
|
2024-03-11 19:26:48 -05:00
|
|
|
impl SignalStore {
|
2024-03-11 18:29:26 -05:00
|
|
|
/// Create a new [`SigIntStore`]
|
2024-03-11 19:26:48 -05:00
|
|
|
pub(crate) fn new() -> Self {
|
2024-03-11 18:29:26 -05:00
|
|
|
Self {
|
|
|
|
sig: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Ensure that store for given signal type exists and return a mutable reference to it
|
|
|
|
fn internal_store<T: UiSignal + 'static>(&mut self) -> &mut Vec<Box<dyn Any>> {
|
|
|
|
let type_id = TypeId::of::<T>();
|
|
|
|
self.sig.entry(type_id).or_default()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add a signal to the store
|
|
|
|
///
|
|
|
|
/// Signals are stored in the order they are added
|
|
|
|
pub fn add<T: UiSignal + 'static>(&mut self, sig: T) {
|
|
|
|
let type_id = TypeId::of::<T>();
|
|
|
|
if let Some(v) = self.sig.get_mut(&type_id) {
|
|
|
|
v.push(Box::new(sig));
|
|
|
|
} else {
|
|
|
|
self.sig.insert(type_id, vec![Box::new(sig)]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Drain all signals of a given type
|
2024-03-11 19:26:48 -05:00
|
|
|
pub(crate) fn drain<T: UiSignal + 'static>(&mut self) -> impl Iterator<Item = T> + '_ {
|
2024-03-11 18:29:26 -05:00
|
|
|
self.internal_store::<T>()
|
|
|
|
.drain(..)
|
|
|
|
.map(|x| *x.downcast::<T>().unwrap()) //unchecked?
|
|
|
|
}
|
2024-03-11 19:40:51 -05:00
|
|
|
|
|
|
|
/// Clear all signals
|
|
|
|
pub(crate) fn clear(&mut self) {
|
|
|
|
//XXX: should we clear the vecs instead?
|
|
|
|
self.sig.clear();
|
|
|
|
}
|
2024-03-11 18:29:26 -05:00
|
|
|
}
|
2024-03-12 13:48:17 -05:00
|
|
|
|
|
|
|
//TODO this, simplifies handling signals
|
|
|
|
|
2024-03-21 12:41:28 -05:00
|
|
|
// pub trait Signal {
|
|
|
|
// type Arg;
|
|
|
|
// type Output;
|
|
|
|
// fn call(&self, arg: Self::Arg) -> Self::Output;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// impl<F: Fn() -> T, T> Signal for F {
|
|
|
|
// type Arg = ();
|
|
|
|
// type Output = T;
|
|
|
|
// fn call(&self, _: Self::Arg) -> Self::Output {
|
|
|
|
// self()
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // impl<F: Fn(A) -> T, A, T> Signal for F {
|
|
|
|
// // type Arg = A;
|
|
|
|
// // type Output = T;
|
|
|
|
// // fn call(&self, a: Self::Arg) -> Self::Output {
|
|
|
|
// // self(a)
|
|
|
|
// // }
|
|
|
|
// // }
|
|
|
|
|
2024-03-14 07:30:44 -05:00
|
|
|
// pub struct SignalTrigger<R: UiSignal + 'static, A = ()>(pub(crate) Box<dyn Fn(A) -> R + 'static>);
|
2024-03-12 13:48:17 -05:00
|
|
|
|
2024-03-14 07:30:44 -05:00
|
|
|
// impl<R: UiSignal + 'static, A> SignalTrigger<R, A> {
|
|
|
|
// pub fn new<F: Fn(A) -> R + 'static>(f: F) -> Self {
|
|
|
|
// Self(Box::new(f))
|
|
|
|
// }
|
2024-03-12 13:48:17 -05:00
|
|
|
|
2024-03-14 07:30:44 -05:00
|
|
|
// pub fn call(&self, a: A) -> R {
|
|
|
|
// (self.0)(a)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// impl<R: UiSignal + 'static, A, T: Fn(A) -> R + 'static> From<T> for SignalTrigger<R, A> {
|
|
|
|
// fn from(f: T) -> Self {
|
|
|
|
// Self(Box::new(f))
|
|
|
|
// }
|
|
|
|
// }
|