123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- use std::rc::{self};
- use std::cell::{RefCell};
- use std::any::{Any};
- use std::marker::{PhantomData};
- use weak_table::{PtrWeakKeyHashMap as WeakMap};
- //////////////////////////////////////////////////////////////////////////////////////////
- // Traits
- /// Event that produces event argument of type A when fired.
- pub trait Evt<A: ?Sized> {
- fn bind<S>(&self, sink: S) where S: Sink<A>;
- }
- /// Sink that may respond to events of type A.
- pub trait Sink<A: ?Sized> {
- fn bind_to_src(self, src: EvtSrc<A>);
- fn bind_to<E>(self, evt: &E) where E: Evt<A>, Self: Sized
- { evt.bind(self) }
- }
- pub trait Callback<T, A: ?Sized>: 'static {
- fn call(&mut self, state: &mut T, arg: &A);
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- // EvtSrc
- /// Source of events with event arguments type A.
- pub struct EvtSrc<A: ?Sized>(PhantomData<A>, rc::Rc<()>);
- impl<A: ?Sized> EvtSrc<A> {
- /// Create a new event source.
- pub fn new() -> Self {
- EvtSrc(PhantomData, rc::Rc::new(()))
- }
- pub fn id(&self) -> &rc::Rc<()> { &self.1 }
- pub fn into_id(self) -> rc::Rc<()> { self.1 }
- }
- impl<A> Evt<A> for EvtSrc<A> {
- fn bind<S>(&self, sink: S) where S: Sink<A> {
- sink.bind_to_src(EvtSrc::clone(self))
- }
- }
- impl<A> Clone for EvtSrc<A> {
- fn clone(&self) -> Self {
- EvtSrc(PhantomData, rc::Rc::clone(&self.1))
- }
- }
- impl<A> PartialEq for EvtSrc<A> {
- fn eq(&self, _: &Self) -> bool { true }
- }
- impl<A> Eq for EvtSrc<A> {}
- //////////////////////////////////////////////////////////////////////////////////////////
- struct DynCallback<T, A: ?Sized>(rc::Rc<RefCell<dyn Callback<T, A>>>);
- // invariant:
- // all RHS bindings to this map should be type Callback<T, A> for some A
- type InternalCallbackMap =
- rc::Rc<RefCell<WeakMap<rc::Weak<()>, Vec<Box<dyn Any>>>>>; // yikes
- pub struct CallbackMap<T: 'static> {
- phantom: PhantomData<T>,
- map: InternalCallbackMap,
- }
- pub struct Dispatcher<'s, T: 'static> {
- state: &'s mut T,
- map: InternalCallbackMap,
- }
- pub struct Registrar<T: 'static> {
- phantom: PhantomData<T>,
- map: InternalCallbackMap,
- }
- //
- impl<T, A: ?Sized> DynCallback<T, A> {
- fn new<C>(cb: C) -> Self where C: Callback<T, A> {
- DynCallback(rc::Rc::new(RefCell::new(cb)))
- }
- }
- impl<T, A: ?Sized> Clone for DynCallback<T, A> {
- fn clone(&self) -> Self {
- DynCallback(self.0.clone())
- }
- }
- impl<T> CallbackMap<T> {
- /// Create a new Dispatcher with given initial state and no bound callbacks.
- pub fn new() -> Self {
- CallbackMap {
- phantom: PhantomData,
- map: rc::Rc::new(RefCell::new(WeakMap::new())),
- }
- }
- pub fn dispatcher<'s>(&mut self, state: &'s mut T) -> Dispatcher<'s, T> {
- Dispatcher { state, map: self.map.clone() }
- }
- pub fn registrar(&mut self) -> Registrar<T> {
- Registrar { phantom: PhantomData, map: self.map.clone() }
- }
- }
- impl<'s, T> Dispatcher<'s, T> {
- /// Fire a given event (source) with given event args passed to each callback.
- pub fn fire<A: ?Sized>(&mut self, evt: &EvtSrc<A>, arg: &A)
- where A: 'static {
- let Dispatcher { state, map } = self;
- let callbacks: Vec<DynCallback<_, _>> =
- map.borrow_mut()
- .get_mut(evt.id())
- .into_iter()
- .flat_map(|rhs| rhs.iter_mut())
- .flat_map(|erased| erased.downcast_mut::<DynCallback<T, A>>().cloned())
- .collect();
- for cb in callbacks {
- cb.0.borrow_mut().call(state, arg);
- }
- }
- }
- impl<T> Registrar<T> {
- /// Create a `Sink<A>` from a callback. The callback can mutate the internal state
- /// of the listener.
- pub fn sink_from_callback<A, C>(&self, callback: C) -> impl Sink<A>
- where A: ?Sized + 'static,
- C: Callback<T, A> {
- CallbackSink { phantom: PhantomData, map: self.map.clone(), callback }
- }
- }
- struct CallbackSink<T, C> {
- phantom: PhantomData<fn(&mut T)>,
- map: InternalCallbackMap,
- callback: C,
- }
- impl<T, A, C> Sink<A> for CallbackSink<T, C>
- where T: 'static,
- A: ?Sized + 'static,
- C: Callback<T, A> + 'static {
- fn bind_to_src(self, src: EvtSrc<A>) {
- bind(self.map, src, self.callback)
- }
- }
- fn bind<T, A, C>(map: InternalCallbackMap, src: EvtSrc<A>, cb: C)
- where T: 'static,
- A: ?Sized + 'static,
- C: Callback<T, A> {
- map.borrow_mut()
- .entry(src.into_id())
- .or_insert_with(Vec::new)
- .push(Box::new(DynCallback::new(cb)));
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- #[cfg(test)]
- mod test {
- use super::*;
- use std::mem::{size_of};
- #[test]
- fn test_static_sizes() {
- let ptr_size = size_of::<*const i32>();
- assert_eq!(size_of::<EvtSrc<()>>(), ptr_size);
- assert_eq!(size_of::<Option<EvtSrc<()>>>(), ptr_size);
- }
- #[test]
- fn test_listener_callback() {
- let mut dsp = Dispatcher::new(vec![]);
- let evt = EvtSrc::new();
- dsp.callback(|state, &arg| state.push(arg))
- .bind_to(&evt);
- dsp.fire(&evt, 1);
- dsp.fire(&evt, 2);
- dsp.fire(&evt, 3);
- assert_eq!(dsp.state(), &[1, 2, 3])
- }
- #[test]
- fn test_listener_heterog() {
- let mut dsp = Dispatcher::new(String::from(""));
- let evt1 = EvtSrc::new();
- let evt2 = EvtSrc::new();
- dsp.callback(|s, &arg| s.push_str(arg))
- .bind_to(&evt1);
- dsp.callback(|s, &arg| s.push_str(&format!("[{:?}]", arg)))
- .bind_to(&evt2);
- dsp.fire(&evt1, "hi");
- dsp.fire(&evt2, 5);
- dsp.fire(&evt1, "world");
- assert_eq!(dsp.state(), "hi[5]world");
- }
- }
|