ori_core/reactive/
callback.rs

1use std::mem;
2
3use crate::{Lock, Lockable, Sendable, Shared, Weak};
4
5struct CallbackCollection<T> {
6    callbacks: Vec<WeakCallback<T>>,
7}
8
9impl<T> Default for CallbackCollection<T> {
10    fn default() -> Self {
11        Self::new()
12    }
13}
14
15impl<T> CallbackCollection<T> {
16    fn new() -> Self {
17        Self {
18            callbacks: Vec::new(),
19        }
20    }
21
22    fn len(&self) -> usize {
23        self.callbacks.len()
24    }
25
26    fn contains(&self, ptr: CallbackPtr<T>) -> bool {
27        for callback in &self.callbacks {
28            if callback.callback.as_ptr() == ptr {
29                return true;
30            }
31        }
32
33        false
34    }
35
36    fn insert(&mut self, callback: WeakCallback<T>) {
37        if !self.contains(callback.callback.as_ptr()) {
38            self.callbacks.push(callback);
39        }
40    }
41
42    fn remove(&mut self, ptr: CallbackPtr<T>) {
43        let equals = |callback: &WeakCallback<T>| callback.callback.as_ptr() != ptr;
44        self.callbacks.retain(equals);
45    }
46}
47
48impl<T> IntoIterator for CallbackCollection<T> {
49    type Item = WeakCallback<T>;
50    type IntoIter = std::vec::IntoIter<Self::Item>;
51
52    fn into_iter(self) -> Self::IntoIter {
53        self.callbacks.into_iter()
54    }
55}
56
57#[cfg(feature = "multithread")]
58type RawCallback<'a, T> = dyn FnMut(&T) + Send + 'a;
59#[cfg(not(feature = "multithread"))]
60type RawCallback<'a, T> = dyn FnMut(&T) + 'a;
61
62type CallbackPtr<T> = *const Lock<RawCallback<'static, T>>;
63type Callbacks<T> = Lock<CallbackCollection<T>>;
64
65/// A callback that can be called from any thread.
66#[derive(Clone)]
67pub struct Callback<'a, T = ()> {
68    callback: Shared<Lock<RawCallback<'a, T>>>,
69}
70
71impl<'a, T> Callback<'a, T> {
72    /// Creates a new callback.
73    pub fn new(callback: impl FnMut(&T) + Sendable + 'a) -> Self {
74        Self {
75            callback: Shared::new(Lock::new(callback)),
76        }
77    }
78
79    /// Downgrades the callback to a [`WeakCallback`].
80    ///
81    /// When the last strong reference is dropped, the callback will be dropped
82    /// and all weak callbacks will be invalidated.
83    pub fn downgrade(&self) -> WeakCallback<T> {
84        // SAFETY: When the last strong reference is dropped, the callback will
85        // be dropped and all weak callbacks will be invalidated. And can therefore
86        // never be called. And since all strong references are tied to the lifetime
87        // of the callback, it is safe to transmute the lifetime to static.
88        let callback = unsafe {
89            mem::transmute::<Weak<Lock<RawCallback<'a, T>>>, Weak<Lock<RawCallback<'static, T>>>>(
90                Shared::downgrade(&self.callback),
91            )
92        };
93        WeakCallback { callback }
94    }
95
96    /// Calls the callback.
97    pub fn emit(&self, event: &T) {
98        self.callback.lock_mut()(event);
99    }
100}
101
102impl<'a, T> Default for Callback<'a, T> {
103    fn default() -> Self {
104        Callback::new(|_| {})
105    }
106}
107
108/// A weak reference to a [`Callback`].
109///
110/// This is usually created by [`Callback::downgrade`].
111#[derive(Clone)]
112pub struct WeakCallback<T = ()> {
113    callback: Weak<Lock<RawCallback<'static, T>>>,
114}
115
116impl<T> WeakCallback<T> {
117    /// Creates a new weak callback from a weak reference.
118    pub fn new(weak: Weak<Lock<RawCallback<'static, T>>>) -> Self {
119        Self { callback: weak }
120    }
121
122    /// Tries to upgrade the weak callback to a [`Callback`].
123    ///
124    /// This will return `None` if all clones of the callback have been dropped.
125    pub fn upgrade(&self) -> Option<Callback<T>> {
126        Some(Callback {
127            callback: self.callback.upgrade()?,
128        })
129    }
130
131    /// Returns the raw pointer to the callback.
132    pub fn as_ptr(&self) -> CallbackPtr<T> {
133        self.callback.as_ptr() as CallbackPtr<T>
134    }
135
136    /// Tries to call the [`Callback`] if it is still alive.
137    ///
138    /// Returns `false` if it fails.
139    pub fn emit(&self, event: &T) -> bool {
140        if let Some(callback) = self.upgrade() {
141            callback.emit(event);
142        }
143
144        self.callback.strong_count() > 0
145    }
146}
147
148impl<T> Default for WeakCallback<T> {
149    fn default() -> Self {
150        // FIXME: this is a hack to get a valid pointer
151        // but it just doesn't feel right
152        Callback::default().downgrade()
153    }
154}
155
156/// A [`Callback`] emitter.
157///
158/// This is used to store a list of callbacks and call them all.
159/// All the callbacks are weak, so they must be kept alive by the user.
160pub struct CallbackEmitter<T = ()> {
161    callbacks: Shared<Callbacks<T>>,
162}
163
164impl<T> Default for CallbackEmitter<T> {
165    fn default() -> Self {
166        Self {
167            callbacks: Shared::new(Lock::new(CallbackCollection::new())),
168        }
169    }
170}
171
172impl<T> Clone for CallbackEmitter<T> {
173    fn clone(&self) -> Self {
174        Self {
175            callbacks: self.callbacks.clone(),
176        }
177    }
178}
179
180impl<T> CallbackEmitter<T> {
181    /// Creates an empty callback emitter.
182    pub fn new() -> Self {
183        Self::default()
184    }
185
186    /// Returns the number of callbacks, valid or not.
187    pub fn len(&self) -> usize {
188        self.callbacks.lock_mut().len()
189    }
190
191    /// Returns `true` if there are no callbacks.
192    pub fn is_empty(&self) -> bool {
193        self.len() == 0
194    }
195
196    /// Downgrades the callback emitter to a [`WeakCallbackEmitter`].
197    pub fn downgrade(&self) -> WeakCallbackEmitter<T> {
198        WeakCallbackEmitter {
199            callbacks: Shared::downgrade(&self.callbacks),
200        }
201    }
202
203    /// Subscribes a callback to the emitter.
204    ///
205    /// The reference to the callback is weak, and will therefore not keep the
206    /// callback alive. If the callback is dropped, it will be removed from the
207    /// emitter.
208    pub fn subscribe(&self, callback: &Callback<'_, T>) {
209        self.subscribe_weak(callback.downgrade());
210    }
211
212    /// Subscribes a weak callback to the emitter.
213    pub fn subscribe_weak(&self, callback: WeakCallback<T>) {
214        self.callbacks.lock_mut().insert(callback);
215    }
216
217    /// Unsubscribes a callback from the emitter.
218    pub fn unsubscribe(&self, ptr: CallbackPtr<T>) {
219        self.callbacks.lock_mut().remove(ptr);
220    }
221
222    /// Clears all the callbacks, and calls them.
223    pub fn emit(&self, event: &T) {
224        let callbacks = mem::take(&mut *self.callbacks.lock_mut());
225
226        for callback in callbacks.into_iter() {
227            if let Some(callback) = callback.upgrade() {
228                callback.emit(event);
229            }
230        }
231    }
232}
233
234impl CallbackEmitter {
235    /// Tracks `self` in the current `effect`.
236    pub fn track(&self) {
237        self.downgrade().track();
238    }
239}
240
241/// A weak reference to a [`CallbackEmitter`].
242///
243/// This is usually created by [`CallbackEmitter::downgrade`].
244pub struct WeakCallbackEmitter<T = ()> {
245    callbacks: Weak<Callbacks<T>>,
246}
247
248impl<T> WeakCallbackEmitter<T> {
249    /// Tries to upgrade the weak callback emitter to a [`CallbackEmitter`].
250    pub fn upgrade(&self) -> Option<CallbackEmitter<T>> {
251        Some(CallbackEmitter {
252            callbacks: self.callbacks.upgrade()?,
253        })
254    }
255}
256
257impl<T> Clone for WeakCallbackEmitter<T> {
258    fn clone(&self) -> Self {
259        Self {
260            callbacks: self.callbacks.clone(),
261        }
262    }
263}
264
265impl WeakCallbackEmitter {
266    /// Tracks `self` in the current **effect**.
267    pub fn track(&self) {
268        super::effect::track_callback(self.clone());
269    }
270}