Skip to main content

ferroui_base/utilities/
i_weak_event_subscriber.rs

1use super::weak_event::WeakEventArgs;
2use super::HandlerList;
3use crate::reactive::{Disposable, IDisposable};
4use std::any::Any;
5use std::rc::{Rc, Weak};
6
7/// Defines a listener to a event subscribed vis the [`WeakEvent`](super::WeakEvent).
8///
9/// `sender` is the object that raised the event, `ev` the weak event it was
10/// raised through (compare it by address with the event, for example
11/// `std::ptr::addr_eq(ev, &*WeakEvents::collection_changed())`).
12pub trait IWeakEventSubscriber<A: WeakEventArgs + ?Sized> {
13    fn on_event(&self, sender: Option<&dyn Any>, ev: &dyn Any, e: &A::Args<'_>);
14}
15
16/// The signature of a handler of [`WeakEventSubscriber::event`] and of the
17/// dispatch function of a [`TargetWeakEventSubscriber`] (after its target).
18pub type WeakEventSubscriberHandler<A> =
19    dyn for<'s, 'v, 'r, 'a> Fn(Option<&'s dyn Any>, &'v dyn Any, &'r <A as WeakEventArgs>::Args<'a>);
20
21/// A subscriber that raises its [`event`](Self::event) for every event it
22/// receives.
23pub struct WeakEventSubscriber<A: WeakEventArgs + ?Sized> {
24    this: Weak<WeakEventSubscriber<A>>,
25    event: HandlerList<WeakEventSubscriberHandler<A>>,
26}
27
28impl<A: WeakEventArgs + ?Sized> WeakEventSubscriber<A> {
29    pub fn new() -> Rc<Self> {
30        Rc::new_cyclic(|this| Self { this: this.clone(), event: HandlerList::new() })
31    }
32
33    /// Subscribes to the events this subscriber receives. Disposing the
34    /// returned handle unsubscribes.
35    pub fn event<F>(&self, handler: F) -> Rc<dyn IDisposable>
36    where
37        F: for<'s, 'v, 'r, 'a> Fn(Option<&'s dyn Any>, &'v dyn Any, &'r A::Args<'a>) + 'static,
38    {
39        let token = self.event.add(Rc::new(handler));
40        let weak = self.this.clone();
41        Disposable::create(move || {
42            if let Some(this) = weak.upgrade() {
43                this.event.remove(token);
44            }
45        })
46    }
47}
48
49impl<A: WeakEventArgs + ?Sized> IWeakEventSubscriber<A> for WeakEventSubscriber<A> {
50    fn on_event(&self, sender: Option<&dyn Any>, ev: &dyn Any, e: &A::Args<'_>) {
51        if self.event.is_empty() {
52            return;
53        }
54        for (_, handler) in self.event.snapshot().iter() {
55            handler(sender, ev, e);
56        }
57    }
58}
59
60/// A subscriber that passes every event it receives to a dispatch function,
61/// together with its target.
62pub struct TargetWeakEventSubscriber<TTarget, A: WeakEventArgs + ?Sized> {
63    target: TTarget,
64    dispatch_func: Box<TargetDispatchFunc<TTarget, A>>,
65}
66
67type TargetDispatchFunc<TTarget, A> =
68    dyn for<'t, 's, 'v, 'r, 'a> Fn(&'t TTarget, Option<&'s dyn Any>, &'v dyn Any, &'r <A as WeakEventArgs>::Args<'a>);
69
70impl<TTarget, A: WeakEventArgs + ?Sized> TargetWeakEventSubscriber<TTarget, A> {
71    pub fn new<F>(target: TTarget, dispatch_func: F) -> Self
72    where
73        F: for<'t, 's, 'v, 'r, 'a> Fn(&'t TTarget, Option<&'s dyn Any>, &'v dyn Any, &'r A::Args<'a>) + 'static,
74    {
75        Self { target, dispatch_func: Box::new(dispatch_func) }
76    }
77}
78
79impl<TTarget, A: WeakEventArgs + ?Sized> IWeakEventSubscriber<A> for TargetWeakEventSubscriber<TTarget, A> {
80    fn on_event(&self, sender: Option<&dyn Any>, ev: &dyn Any, e: &A::Args<'_>) {
81        (self.dispatch_func)(&self.target, sender, ev, e);
82    }
83}