Skip to main content

ferroui_base/utilities/
handler_list.rs

1use std::cell::{Cell, RefCell};
2use std::rc::Rc;
3
4/// A list of event handlers that tolerates being modified while it is being
5/// invoked: invocation works on a snapshot, and the snapshot is only copied
6/// when the list actually changes.
7pub struct HandlerList<F: ?Sized> {
8    handlers: RefCell<Rc<Vec<(u64, Rc<F>)>>>,
9    next_id: HandlerIds,
10}
11
12/// Where the tokens of a handler list come from.
13enum HandlerIds {
14    Own(Cell<u64>),
15    /// A counter shared with other lists, so that tokens across them are in
16    /// subscription order (the typed and untyped forms of one event).
17    Shared(Rc<Cell<u64>>),
18}
19
20impl HandlerIds {
21    fn next(&self) -> u64 {
22        let cell = match self {
23            Self::Own(cell) => cell,
24            Self::Shared(cell) => cell,
25        };
26        let id = cell.get();
27        cell.set(id + 1);
28        id
29    }
30}
31
32impl<F: ?Sized> Default for HandlerList<F> {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38impl<F: ?Sized> HandlerList<F> {
39    pub fn new() -> Self {
40        Self { handlers: RefCell::new(Rc::new(Vec::new())), next_id: HandlerIds::Own(Cell::new(1)) }
41    }
42
43    /// A list whose tokens come from `ids`, a counter shared with other
44    /// lists: tokens across all of them increase in subscription order.
45    pub fn with_shared_ids(ids: Rc<Cell<u64>>) -> Self {
46        Self { handlers: RefCell::new(Rc::new(Vec::new())), next_id: HandlerIds::Shared(ids) }
47    }
48
49    #[inline]
50    pub fn is_empty(&self) -> bool {
51        self.handlers.borrow().is_empty()
52    }
53
54    pub fn len(&self) -> usize {
55        self.handlers.borrow().len()
56    }
57
58    /// Adds a handler and returns a token that removes it again.
59    pub fn add(&self, handler: Rc<F>) -> u64 {
60        let id = self.next_id.next();
61        let mut handlers = self.handlers.borrow_mut();
62        Rc::make_mut_or_clone(&mut handlers).push((id, handler));
63        id
64    }
65
66    /// Removes the handler registered under `token`.
67    pub fn remove(&self, token: u64) -> bool {
68        let mut handlers = self.handlers.borrow_mut();
69        match handlers.iter().position(|(id, _)| *id == token) {
70            Some(index) => {
71                Rc::make_mut_or_clone(&mut handlers).remove(index);
72                true
73            }
74            None => false,
75        }
76    }
77
78    /// Returns the current handlers; later modifications do not affect it.
79    #[inline]
80    pub fn snapshot(&self) -> Rc<Vec<(u64, Rc<F>)>> {
81        self.handlers.borrow().clone()
82    }
83}
84
85trait MakeMutOrClone<T> {
86    fn make_mut_or_clone(this: &mut Self) -> &mut T;
87}
88
89impl<F: ?Sized> MakeMutOrClone<Vec<(u64, Rc<F>)>> for Rc<Vec<(u64, Rc<F>)>> {
90    fn make_mut_or_clone(this: &mut Self) -> &mut Vec<(u64, Rc<F>)> {
91        if Rc::get_mut(this).is_none() {
92            let copy: Vec<(u64, Rc<F>)> = this.iter().map(|(id, f)| (*id, f.clone())).collect();
93            *this = Rc::new(copy);
94        }
95        Rc::get_mut(this).expect("uniquely owned after copy")
96    }
97}