ori_core/reactive/
signal.rs

1use std::{
2    cmp::Ordering,
3    fmt::{Debug, Formatter},
4    hash::{Hash, Hasher},
5    ops::{Deref, DerefMut},
6    panic::Location,
7};
8
9use crate::{CallbackEmitter, Lock, Lockable, Shared, Weak};
10
11/// A read-only [`Signal`].
12pub struct ReadSignal<T: ?Sized> {
13    value: Lock<Shared<T>>,
14    emitter: CallbackEmitter,
15}
16
17impl<T> ReadSignal<T> {
18    /// Creates a new [`ReadSignal`] from a value.
19    pub fn new(value: T) -> Self {
20        Self::new_arc(Shared::new(value))
21    }
22}
23
24impl<T: ?Sized> ReadSignal<T> {
25    /// Creates a new [`ReadSignal`] from an [`Shared`].
26    pub fn new_arc(value: Shared<T>) -> Self {
27        Self {
28            value: Lock::new(value),
29            emitter: CallbackEmitter::new(),
30        }
31    }
32
33    /// Gets the [`CallbackEmitter`] for this [`ReadSignal`].
34    pub fn emitter(&self) -> &CallbackEmitter {
35        &self.emitter
36    }
37
38    /// Tracks `self` in the currently running `effect`.
39    pub fn track(&self) {
40        self.emitter.track();
41    }
42
43    /// Gets the current value of `self`.
44    ///
45    /// This will track `self` in the currently running `effect`.
46    pub fn get(&self) -> Shared<T> {
47        self.emitter.track();
48        self.get_untracked()
49    }
50
51    /// Gets the current value of `self` without tracking it.
52    pub fn get_untracked(&self) -> Shared<T> {
53        self.value.lock_mut().clone()
54    }
55}
56
57impl<T: Clone> ReadSignal<T> {
58    /// Returns a clone of the current value of `self`.
59    ///
60    /// This will track `self` in the currently running `effect`.
61    pub fn cloned(&self) -> T {
62        self.get().as_ref().clone()
63    }
64
65    /// Returns a clone of the current value of `self` without tracking it.
66    pub fn cloned_untracked(&self) -> T {
67        self.get_untracked().as_ref().clone()
68    }
69}
70
71impl<T: Copy> ReadSignal<T> {
72    /// Returns a copy to the current value of `self`.
73    pub fn copied(&self) -> T {
74        *self.get().as_ref()
75    }
76
77    /// Returns a copy to the current value of `self`.
78    pub fn copied_untracked(&self) -> T {
79        *self.get_untracked().as_ref()
80    }
81}
82
83/// A [`Signal`] that can be written to.
84///
85/// This is a wrapper around [`ReadSignal`].
86///
87/// Signals are used to store state that can be read from and written to.
88/// Using [`ReadSignal::get()`] and [`Signal::set()`]. Getting the value of a signal
89/// will track the signal in the currently running `effect`, and setting the
90/// value of a signal will trigger all the callbacks and effects, that are subscribed to
91/// the signal.
92///
93/// # Example
94/// ```
95/// # use ori_core::*;
96/// # Scope::immediate(|cx| {
97/// // create a new signal
98/// let signal = cx.signal(0);
99///
100/// // create a new effect
101/// cx.effect(|| {
102///     // this will be called when it's created
103///     // and every time the signal is set
104///     println!("signal value: {}", signal.get());
105/// });
106///
107/// // set the signal to 1
108/// // this will trigger the effect
109/// signal.set(1);
110/// # });
111/// ```
112pub struct Signal<T: ?Sized>(ReadSignal<T>);
113
114impl<T> Signal<T> {
115    /// Creates a new [`Signal`] from a value.
116    pub fn new(value: T) -> Self {
117        Self(ReadSignal::new(value))
118    }
119
120    /// Sets the value of `self`.
121    #[track_caller]
122    pub fn set(&self, value: T) {
123        self.set_arc(Shared::new(value));
124    }
125
126    /// Sets the value of `self` without triggering the callbacks.
127    pub fn set_silent(&self, value: T) {
128        self.set_arc_silent(Shared::new(value));
129    }
130}
131
132impl<T: ?Sized> Signal<T> {
133    /// Creates a new [`Signal`] from an [`Shared`].
134    pub fn new_arc(value: Shared<T>) -> Self {
135        Self(ReadSignal::new_arc(value))
136    }
137
138    /// Sets the value of `self` to an [`Shared`].
139    #[track_caller]
140    pub fn set_arc(&self, value: Shared<T>) {
141        self.set_arc_silent(value.clone());
142        self.emit();
143    }
144
145    /// Sets the value of `self` to an [`Shared`] without triggering the callbacks.
146    pub fn set_arc_silent(&self, value: Shared<T>) {
147        *self.value.lock_mut() = value;
148    }
149
150    /// Emits the [`CallbackEmitter`] for this [`Signal`].
151    #[track_caller]
152    pub fn emit(&self) {
153        let location = Location::caller();
154        tracing::trace!("emitting signal at {}", location);
155
156        self.emitter.emit(&());
157    }
158}
159
160impl<T: ?Sized> Deref for Signal<T> {
161    type Target = ReadSignal<T>;
162
163    fn deref(&self) -> &Self::Target {
164        &self.0
165    }
166}
167
168#[derive(Debug)]
169pub struct Modify<'a, T> {
170    value: Option<T>,
171    signal: &'a Signal<T>,
172}
173
174impl<'a, T> Deref for Modify<'a, T> {
175    type Target = T;
176
177    #[track_caller]
178    fn deref(&self) -> &Self::Target {
179        self.value.as_ref().unwrap()
180    }
181}
182
183impl<'a, T> DerefMut for Modify<'a, T> {
184    #[track_caller]
185    fn deref_mut(&mut self) -> &mut Self::Target {
186        self.value.as_mut().unwrap()
187    }
188}
189
190/// When the [`Modify`] is dropped, update the [`Signal`].
191impl<'a, T> Drop for Modify<'a, T> {
192    fn drop(&mut self) {
193        self.signal.set(self.value.take().unwrap());
194    }
195}
196
197impl<T: Clone> Signal<T> {
198    /// Returns a [`Modify`] that can be used to modify the value of the [`Signal`].
199    /// When the [`Modify`] is dropped, the [`Signal`] will be updated.
200    pub fn modify(&self) -> Modify<'_, T> {
201        Modify {
202            value: Some(self.get().as_ref().clone()),
203            signal: self,
204        }
205    }
206}
207
208/// A [`Signal`] that can be cloned.
209pub struct SharedSignal<T: ?Sized>(Shared<Signal<T>>);
210
211impl<T> SharedSignal<T> {
212    pub fn new(value: T) -> Self {
213        Self(Shared::new(Signal::new(value)))
214    }
215}
216
217impl<T: ?Sized> SharedSignal<T> {
218    pub fn new_arc(value: Shared<T>) -> Self {
219        Self(Shared::new(Signal::new_arc(value)))
220    }
221
222    pub fn downgrade(&self) -> WeakSignal<T> {
223        WeakSignal(Shared::downgrade(&self.0))
224    }
225}
226
227impl<T: ?Sized> Clone for SharedSignal<T> {
228    fn clone(&self) -> Self {
229        Self(self.0.clone())
230    }
231}
232
233impl<T: ?Sized> Deref for SharedSignal<T> {
234    type Target = Signal<T>;
235
236    fn deref(&self) -> &Self::Target {
237        &self.0
238    }
239}
240
241/// A weak reference to a [`Signal`].
242pub struct WeakSignal<T: ?Sized>(Weak<Signal<T>>);
243
244impl<T> WeakSignal<T> {
245    #[track_caller]
246    pub fn set(&self, value: T) {
247        if let Some(signal) = self.upgrade() {
248            signal.set(value);
249        }
250    }
251
252    pub fn set_silent(&self, value: T) {
253        if let Some(signal) = self.upgrade() {
254            signal.set_silent(value);
255        }
256    }
257}
258
259impl<T: ?Sized> WeakSignal<T> {
260    pub fn upgrade(&self) -> Option<SharedSignal<T>> {
261        self.0.upgrade().map(SharedSignal)
262    }
263
264    #[track_caller]
265    pub fn set_arc(&self, value: Shared<T>) {
266        if let Some(signal) = self.upgrade() {
267            signal.set_arc(value);
268        }
269    }
270
271    pub fn set_arc_silent(&self, value: Shared<T>) {
272        if let Some(signal) = self.upgrade() {
273            signal.set_arc_silent(value);
274        }
275    }
276
277    pub fn get(&self) -> Option<Shared<T>> {
278        Some(self.upgrade()?.get())
279    }
280
281    pub fn get_untracked(&self) -> Option<Shared<T>> {
282        Some(self.upgrade()?.get_untracked())
283    }
284}
285
286impl<T: ?Sized> Clone for WeakSignal<T> {
287    fn clone(&self) -> Self {
288        Self(self.0.clone())
289    }
290}
291
292impl<T: Debug + ?Sized> Debug for ReadSignal<T> {
293    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
294        f.debug_tuple("ReadSignal").field(&self.get()).finish()
295    }
296}
297
298impl<T: Debug + ?Sized> Debug for Signal<T> {
299    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
300        f.debug_tuple("Signal").field(&self.get()).finish()
301    }
302}
303
304impl<T: Debug + ?Sized> Debug for SharedSignal<T> {
305    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
306        f.debug_tuple("SharedSignal").field(&self.get()).finish()
307    }
308}
309
310impl<T: Debug + ?Sized> Debug for WeakSignal<T> {
311    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
312        f.debug_tuple("WeakSignal").field(&self.get()).finish()
313    }
314}
315
316impl<T: Default> Default for ReadSignal<T> {
317    fn default() -> Self {
318        Self::new(T::default())
319    }
320}
321
322impl<T: Default> Default for Signal<T> {
323    fn default() -> Self {
324        Self::new(T::default())
325    }
326}
327
328impl<T: Default> Default for SharedSignal<T> {
329    fn default() -> Self {
330        Self::new(T::default())
331    }
332}
333
334impl<T: PartialEq + ?Sized> PartialEq for ReadSignal<T> {
335    fn eq(&self, other: &Self) -> bool {
336        self.get() == other.get()
337    }
338}
339
340impl<T: PartialEq + ?Sized> PartialEq for Signal<T> {
341    fn eq(&self, other: &Self) -> bool {
342        self.get() == other.get()
343    }
344}
345
346impl<T: PartialEq + ?Sized> PartialEq for SharedSignal<T> {
347    fn eq(&self, other: &Self) -> bool {
348        self.get() == other.get()
349    }
350}
351
352impl<T: PartialEq + ?Sized> PartialEq for WeakSignal<T> {
353    fn eq(&self, other: &Self) -> bool {
354        self.get() == other.get()
355    }
356}
357
358impl<T: PartialEq + ?Sized> PartialEq<T> for ReadSignal<T> {
359    fn eq(&self, other: &T) -> bool {
360        self.get().as_ref() == other
361    }
362}
363
364impl<T: PartialEq + ?Sized> PartialEq<T> for Signal<T> {
365    fn eq(&self, other: &T) -> bool {
366        self.get().as_ref() == other
367    }
368}
369
370impl<T: PartialEq + ?Sized> PartialEq<T> for SharedSignal<T> {
371    fn eq(&self, other: &T) -> bool {
372        self.get().as_ref() == other
373    }
374}
375
376impl<T: Eq + ?Sized> Eq for ReadSignal<T> {}
377impl<T: Eq + ?Sized> Eq for Signal<T> {}
378impl<T: Eq + ?Sized> Eq for SharedSignal<T> {}
379
380impl<T: PartialOrd + ?Sized> PartialOrd for ReadSignal<T> {
381    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
382        self.get().partial_cmp(&other.get())
383    }
384}
385
386impl<T: PartialOrd + ?Sized> PartialOrd for Signal<T> {
387    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
388        self.get().partial_cmp(&other.get())
389    }
390}
391
392impl<T: PartialOrd + ?Sized> PartialOrd for SharedSignal<T> {
393    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
394        self.get().partial_cmp(&other.get())
395    }
396}
397
398impl<T: PartialOrd + ?Sized> PartialOrd<T> for ReadSignal<T> {
399    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
400        self.get().as_ref().partial_cmp(other)
401    }
402}
403
404impl<T: PartialOrd + ?Sized> PartialOrd<T> for Signal<T> {
405    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
406        self.get().as_ref().partial_cmp(other)
407    }
408}
409
410impl<T: PartialOrd + ?Sized> PartialOrd<T> for SharedSignal<T> {
411    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
412        self.get().as_ref().partial_cmp(other)
413    }
414}
415
416impl<T: Ord + ?Sized> Ord for ReadSignal<T> {
417    fn cmp(&self, other: &Self) -> Ordering {
418        self.get().cmp(&other.get())
419    }
420}
421
422impl<T: Ord + ?Sized> Ord for Signal<T> {
423    fn cmp(&self, other: &Self) -> Ordering {
424        self.get().cmp(&other.get())
425    }
426}
427
428impl<T: Ord + ?Sized> Ord for SharedSignal<T> {
429    fn cmp(&self, other: &Self) -> Ordering {
430        self.get().cmp(&other.get())
431    }
432}
433
434impl<T: Hash + ?Sized> Hash for ReadSignal<T> {
435    fn hash<H: Hasher>(&self, state: &mut H) {
436        self.get().hash(state);
437    }
438}
439
440impl<T: Hash + ?Sized> Hash for Signal<T> {
441    fn hash<H: Hasher>(&self, state: &mut H) {
442        self.get().hash(state);
443    }
444}
445
446impl<T: Hash + ?Sized> Hash for SharedSignal<T> {
447    fn hash<H: Hasher>(&self, state: &mut H) {
448        self.get().hash(state);
449    }
450}
451
452impl<T: Hash + ?Sized> Hash for WeakSignal<T> {
453    fn hash<H: Hasher>(&self, state: &mut H) {
454        self.get().hash(state);
455    }
456}