Skip to main content

fui_core/observable/
event.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3use std::rc::Weak;
4
5use crate::Callback;
6
7///
8/// EventSubscription is an owner of the callback (handler).
9/// Event keeps only a weak reference to the callback (handler).
10///
11/// Calling the callback stops when EventSubscription is dropped.
12///
13/// EventSubscription can keep more than one callback internally.
14/// It is useful when implementing aggregation of events.
15///
16pub struct EventSubscription {
17    _callbacks: Vec<Rc<dyn CallbackObject>>,
18}
19
20impl EventSubscription {
21    pub fn from_many(event_subscriptions: Vec<EventSubscription>) -> Self {
22        let mut callbacks = Vec::new();
23        for mut subscription in event_subscriptions.into_iter() {
24            callbacks.append(&mut subscription._callbacks);
25        }
26        EventSubscription {
27            _callbacks: callbacks,
28        }
29    }
30}
31
32impl Drop for EventSubscription {
33    fn drop(&mut self) {}
34}
35
36pub trait CallbackObject {}
37impl<A> CallbackObject for Callback<A> {}
38
39pub struct Event<A> {
40    callbacks: RefCell<Vec<Weak<Callback<A>>>>,
41}
42
43impl<A: 'static + Clone> Event<A> {
44    pub fn new() -> Self {
45        Event {
46            callbacks: RefCell::new(Vec::new()),
47        }
48    }
49
50    pub fn subscribe<F: 'static + FnMut(A)>(&mut self, f: F) -> EventSubscription {
51        let mut callback = Callback::<A>::empty();
52        callback.set_sync(f);
53        let rc_callback = Rc::new(callback);
54        let weak_callback = Rc::downgrade(&rc_callback);
55        self.callbacks.borrow_mut().push(weak_callback);
56
57        EventSubscription {
58            _callbacks: vec![rc_callback],
59        }
60    }
61
62    pub fn emit(&self, args: A) {
63        let mut cleanup = false;
64
65        for weak_callback in self.callbacks.borrow().iter() {
66            match weak_callback.upgrade() {
67                Some(callback) => {
68                    callback.emit(args.clone());
69                }
70                _ => {
71                    cleanup = true;
72                }
73            }
74        }
75
76        if cleanup {
77            self.callbacks.borrow_mut().retain(|weak_callback| {
78                let got_ref = weak_callback.clone().upgrade();
79                match got_ref {
80                    None => false,
81                    _ => true,
82                }
83            });
84        }
85    }
86}