1use std::cell::{Cell, RefCell};
8use std::rc::{Rc, Weak};
9
10type Callback = Rc<dyn Fn()>;
11
12#[derive(Default)]
13pub struct Subscribers {
15 next_id: Cell<u64>,
16 callbacks: RefCell<Vec<(u64, Callback)>>,
17}
18
19impl Subscribers {
20 pub fn subscribe(self: &Rc<Self>, callback: impl Fn() + 'static) -> Subscription {
22 let id = self.next_id.get();
23 self.next_id.set(id + 1);
24 self.callbacks.borrow_mut().push((id, Rc::new(callback)));
25 Subscription {
26 list: Rc::downgrade(self),
27 id,
28 }
29 }
30
31 pub fn notify(&self) {
33 let callbacks: Vec<Callback> = self
34 .callbacks
35 .borrow()
36 .iter()
37 .map(|(_, c)| c.clone())
38 .collect();
39 for callback in callbacks {
40 callback();
41 }
42 }
43}
44
45#[must_use = "dropping a Subscription unsubscribes immediately"]
47pub struct Subscription {
48 list: Weak<Subscribers>,
49 id: u64,
50}
51
52impl Subscription {
53 pub fn detach(self) {
55 std::mem::forget(self);
56 }
57}
58
59impl Drop for Subscription {
60 fn drop(&mut self) {
61 if let Some(list) = self.list.upgrade() {
62 list.callbacks.borrow_mut().retain(|(id, _)| *id != self.id);
63 }
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn dropping_the_guard_unsubscribes_and_reentrant_subscribe_is_safe() {
73 let list = Rc::new(Subscribers::default());
74 let count = Rc::new(Cell::new(0));
75 let inner: Rc<RefCell<Vec<Subscription>>> = Rc::default();
76 let guard = {
77 let (count, list2, inner) = (count.clone(), list.clone(), inner.clone());
78 list.subscribe(move || {
79 count.set(count.get() + 1);
80 inner.borrow_mut().push(list2.subscribe(|| {}));
81 })
82 };
83 list.notify();
84 assert_eq!(count.get(), 1);
85 drop(guard);
86 list.notify();
87 assert_eq!(count.get(), 1);
88 }
89}