agility/
signal.rs

1use std::{cell::RefCell, iter, rc::Rc};
2
3use crate::api::Liftable;
4
5pub(crate) trait SignalExt<'a> {
6    fn react(&self);
7    fn guard(&self) -> SignalGuard<'a>;
8    fn decrease_dirty(&self);
9    fn get_dirty(&self) -> isize;
10    fn clone_box(&self) -> Box<dyn SignalExt<'a> + 'a>;
11    fn collect_guards_recursive(&self, result: &mut Vec<SignalGuardInner<'a>>);
12    fn collect_predecessors_recursive(&self, result: &mut Vec<SignalGuardInner<'a>>);
13    fn reset_explicitly_modified(&self);
14}
15
16pub(crate) trait RefStrategy<'a> {
17    type Ref<T: 'a>: 'a;
18    fn new_ref<T: 'a>(inner: &Rc<SignalInner<'a, T>>) -> Self::Ref<T>;
19    fn upgrade<T: 'a>(ref_: &Self::Ref<T>) -> Option<Rc<SignalInner<'a, T>>>;
20}
21
22pub(crate) struct WeakRefStrategy;
23
24impl<'a> RefStrategy<'a> for WeakRefStrategy {
25    type Ref<T: 'a> = std::rc::Weak<SignalInner<'a, T>>;
26
27    fn new_ref<T: 'a>(inner: &Rc<SignalInner<'a, T>>) -> Self::Ref<T> {
28        Rc::downgrade(inner)
29    }
30
31    fn upgrade<T: 'a>(ref_: &Self::Ref<T>) -> Option<Rc<SignalInner<'a, T>>> {
32        ref_.upgrade()
33    }
34}
35
36pub(crate) struct StrongRefStrategy;
37
38impl<'a> RefStrategy<'a> for StrongRefStrategy {
39    type Ref<T: 'a> = Rc<SignalInner<'a, T>>;
40
41    fn new_ref<T: 'a>(inner: &Rc<SignalInner<'a, T>>) -> Self::Ref<T> {
42        inner.clone()
43    }
44
45    fn upgrade<T: 'a>(ref_: &Self::Ref<T>) -> Option<Rc<SignalInner<'a, T>>> {
46        Some(ref_.clone())
47    }
48}
49
50pub(crate) struct WeakSignalRef<'a> {
51    upgrade: Box<dyn Fn() -> Option<Box<dyn SignalExt<'a> + 'a>> + 'a>,
52}
53
54impl<'a> WeakSignalRef<'a> {
55    pub fn new<T: 'a>(signal: &Signal<'a, T>) -> Self {
56        let weak = Rc::downgrade(&signal.0);
57        WeakSignalRef {
58            upgrade: Box::new(move || {
59                weak.upgrade()
60                    .map(|rc| Box::new(Signal(rc)) as Box<dyn SignalExt<'a> + 'a>)
61            }),
62        }
63    }
64
65    pub fn upgrade(&self) -> Option<Box<dyn SignalExt<'a> + 'a>> {
66        (self.upgrade)()
67    }
68
69    pub fn is_alive(&self) -> bool {
70        self.upgrade().is_some()
71    }
72}
73
74/// The inner part of a signal guard
75pub struct SignalGuardInner<'a>(Box<dyn SignalExt<'a> + 'a>);
76
77/// Signal guard that triggers reactions on drop
78#[allow(dead_code)]
79#[allow(unused_must_use)]
80pub struct SignalGuard<'a>(Vec<SignalGuardInner<'a>>);
81
82impl<'a> SignalGuard<'a> {
83    /// Combine two signal guards into one
84    pub fn and(mut self, mut other: SignalGuard<'a>) -> SignalGuard<'a> {
85        self.0.append(&mut other.0);
86        self
87    }
88}
89
90impl<'a> Drop for SignalGuardInner<'a> {
91    fn drop(&mut self) {
92        self.0.decrease_dirty();
93        if self.0.get_dirty() == 0 {
94            self.0.react();
95            self.0.reset_explicitly_modified();
96        }
97    }
98}
99
100impl<'a> Drop for SignalGuard<'a> {
101    fn drop(&mut self) {
102        // First drop all inner guards (triggers immediate reactions)
103        drop(std::mem::take(&mut self.0));
104    }
105}
106
107/// The inner data of a signal
108pub struct SignalInner<'a, T> {
109    pub(crate) value: RefCell<T>,
110    pub(crate) react_fns: RefCell<Vec<Box<dyn Fn() + 'a>>>,
111    pub(crate) successors: RefCell<Vec<WeakSignalRef<'a>>>,
112    pub(crate) predecessors: RefCell<Vec<WeakSignalRef<'a>>>,
113    pub(crate) dirty: RefCell<isize>,
114    pub(crate) explicitly_modified: RefCell<bool>,
115}
116
117/// Signal representing a reactive value
118pub struct Signal<'a, T>(pub(crate) Rc<SignalInner<'a, T>>);
119
120impl<'a, T: 'a> Signal<'a, T> {
121    /// Create a new signal with the given initial value
122    pub fn new(initial: T) -> Self {
123        let inner = Rc::new(SignalInner {
124            value: RefCell::new(initial),
125            react_fns: RefCell::new(Vec::new()),
126            successors: RefCell::new(Vec::new()),
127            predecessors: RefCell::new(Vec::new()),
128            dirty: RefCell::new(0),
129            explicitly_modified: RefCell::new(false),
130        });
131        Signal(inner)
132    }
133
134    /// Helper: Temporarily take value without cloning using MaybeUninit
135    #[inline]
136    fn take_value<U>(cell: &RefCell<U>) -> U {
137        let mut temp = unsafe { std::mem::MaybeUninit::<U>::uninit().assume_init() };
138        std::mem::swap(&mut *cell.borrow_mut(), &mut temp);
139        temp
140    }
141
142    /// Send a new value to the signal
143    ///
144    /// This will replace the current value of the signal with the new value.
145    /// The signals that depend on this signal will be notified and updated accordingly.
146    ///
147    /// It returns a `SignalGuard` that ensures reactions are processed when dropped and
148    /// prevents premature reactions during multiple sends. (Batch updates)
149    /// # Example
150    /// ```rust
151    /// let signal = Signal::new(0);
152    /// signal.send(42); // sets the signal's value to 42
153    ///
154    /// signal.with(|v| println!("Signal value: {}", v));
155    /// (signal.send(66), signal.send(100));
156    /// // sets the signal's value to 100 and prints "Signal value: 100" only once
157    /// ```
158    pub fn send(&self, new_value: T) -> SignalGuard<'a> {
159        self.modify(|v| *v = new_value);
160        *self.0.explicitly_modified.borrow_mut() = true;
161        self.guard()
162    }
163
164    /// Send a modification to the signal
165    ///
166    /// This will apply the provided function to modify the current value of the signal.
167    /// The signals that depend on this signal will be notified and updated accordingly.
168    ///
169    /// It returns a `SignalGuard` that ensures reactions are processed when dropped and
170    /// prevents premature reactions during multiple sends. (Batch updates)
171    pub fn send_with<F>(&self, f: F) -> SignalGuard<'a>
172    where
173        F: FnOnce(&mut T),
174    {
175        self.modify(f);
176        self.guard()
177    }
178
179    pub fn set(&mut self, signal: Signal<'a, T>) {
180        self.0 = signal.0;
181    }
182
183    /// Map the signal to a new signal
184    ///
185    /// This creates a new signal that depends on the current signal.
186    /// Changes to the source signal will propagate to the new signal.
187    ///
188    /// # Example
189    /// ```rust
190    /// let a = Signal::new(10);
191    /// let b = a.map(|x| x * 2);
192    /// let _observer = b.map(|x| println!("b changed: {}", x));
193    /// a.send(5); // prints "b changed: 10"
194    /// ```
195    pub fn map<U: 'a, F>(&self, f: F) -> Signal<'a, U>
196    where
197        F: Fn(&T) -> U + 'a,
198    {
199        self.map_ref::<U, F, WeakRefStrategy>(f)
200    }
201
202    /// Map the signal to a new signal with strong references
203    ///
204    /// This creates a new signal that depends on the current signal.
205    /// Changes to the source signal will propagate to the new signal.
206    /// This mapping uses strong references.
207    ///
208    /// # Example
209    /// ```rust
210    /// let a = Signal::new(10);
211    /// let b = a.map(|x| x * 2);
212    /// b.with(|x| println!("b changed: {}", x));
213    /// a.send(5); // prints "b changed: 10"
214    /// ```
215    pub fn with<U: 'a, F>(&self, f: F) -> Signal<'a, U>
216    where
217        F: Fn(&T) -> U + 'a,
218    {
219        self.map_ref::<U, F, StrongRefStrategy>(f)
220    }
221
222    fn map_ref<U: 'a, F, S: RefStrategy<'a>>(&self, f: F) -> Signal<'a, U>
223    where
224        F: Fn(&T) -> U + 'a,
225    {
226        let new_signal = Signal::new(f(&self.0.value.borrow()));
227        let result_new_signal = new_signal.clone();
228
229        let new_signal_ref = S::new_ref(&new_signal.0);
230        let source_ref = S::new_ref(&self.0);
231
232        let react_fn = Box::new(move || {
233            if let Some(new_sig_inner) = S::upgrade(&new_signal_ref) {
234                if !*new_sig_inner.explicitly_modified.borrow() {
235                    if let Some(src_inner) = S::upgrade(&source_ref) {
236                        let new_value = f(&src_inner.value.borrow());
237                        *new_sig_inner.value.borrow_mut() = new_value;
238                    }
239                }
240            }
241        });
242
243        self.0.react_fns.borrow_mut().push(react_fn);
244        self.0
245            .successors
246            .borrow_mut()
247            .push(WeakSignalRef::new(&new_signal));
248
249        result_new_signal
250    }
251
252    /// Map the signal contravariantly to a new signal
253    ///
254    /// This creates a new signal that the current signal depends on.
255    /// Changes to the new signal will propagate back to the original signal.
256    /// It is inspired by the concept of contravariant functors in category theory.
257    ///
258    /// # Example
259    /// ```rust
260    /// let result = Signal::new(42);
261    /// let source = result.contramap(|x| x * 2);
262    /// result.with(|x| println!("result changed: {}", x));
263    /// source.with(|x| println!("source changed: {}", x));
264    /// source.send(100);
265    /// // prints "source changed: 100" and "result changed: 50"
266    /// ```
267    pub fn contramap<F, U>(&self, f: F) -> Signal<'a, U>
268    where
269        F: Fn(&U) -> T + 'a,
270        U: Default + 'a,
271    {
272        let new_signal = Signal::new(U::default());
273        let result_new_signal = new_signal.clone();
274        let source_inner = Rc::downgrade(&self.0);
275        let new_signal_rc = Rc::downgrade(&new_signal.0);
276
277        let react_fn = Box::new(move || {
278            if let Some(new_sig) = new_signal_rc.upgrade() {
279                if *new_sig.explicitly_modified.borrow() {
280                    let u_value_ref = new_sig.value.borrow();
281                    let t_value = f(&u_value_ref);
282                    drop(u_value_ref);
283
284                    if let Some(source) = source_inner.upgrade() {
285                        *source.value.borrow_mut() = t_value;
286                        *source.explicitly_modified.borrow_mut() = true;
287                    }
288                }
289            }
290        });
291        new_signal.0.react_fns.borrow_mut().push(react_fn);
292
293        new_signal
294            .0
295            .predecessors
296            .borrow_mut()
297            .push(WeakSignalRef::new(self));
298
299        result_new_signal
300    }
301
302    /// Map the signal bidirectionally to a new signal
303    ///
304    /// This creates a new signal that depends on the current signal,
305    /// and the current signal also depends on the new signal.
306    /// Changes to either signal will propagate to the other signal.
307    /// It is inspired by the concept of profunctors in category theory.
308    ///
309    /// # Example
310    /// ```rust
311    /// let a = Signal::new(10);
312    /// let b = a.promap(|x| x * 2, |y| y / 2);
313    /// a.with(|x| println!("a changed: {}", x));
314    /// b.with(|x| println!("b changed: {}", x));
315    /// a.send(5); // prints "a changed: 5" and "b changed: 10"
316    /// b.send(50); // prints "b changed: 50" and "a changed: 25"
317    /// ```
318    pub fn promap<F, G, U>(&self, f: F, g: G) -> Signal<'a, U>
319    where
320        F: Fn(&T) -> U + 'a,
321        G: Fn(&U) -> T + 'a,
322        U: Default + 'a,
323    {
324        let new_signal = Signal::new(U::default());
325        let result_new_signal = new_signal.clone();
326        let source_weak = Rc::downgrade(&self.0);
327        let new_signal_weak = Rc::downgrade(&new_signal.0);
328
329        // Forward reaction: T -> U (covariant)
330        let source_inner = source_weak.clone();
331        let new_signal_rc = new_signal_weak.clone();
332        let forward_react_fn = Box::new(move || {
333            if let Some(new_sig) = new_signal_rc.upgrade() {
334                if !*new_sig.explicitly_modified.borrow() {
335                    if let Some(source) = source_inner.upgrade() {
336                        let t_value = source.value.borrow();
337                        let u_value = f(&t_value);
338                        drop(t_value);
339                        *new_sig.value.borrow_mut() = u_value;
340                    }
341                }
342            }
343        });
344
345        self.0.react_fns.borrow_mut().push(forward_react_fn);
346        self.0
347            .successors
348            .borrow_mut()
349            .push(WeakSignalRef::new(&new_signal));
350
351        // Backward reaction: U -> T (contravariant)
352        let new_signal_rc_back = new_signal_weak.clone();
353        let source_inner_back = source_weak.clone();
354
355        let backward_react_fn = Box::new(move || {
356            if let Some(new_sig) = new_signal_rc_back.upgrade() {
357                if *new_sig.explicitly_modified.borrow() {
358                    let u_value_ref = new_sig.value.borrow();
359                    let t_value = g(&u_value_ref);
360                    drop(u_value_ref);
361
362                    if let Some(source) = source_inner_back.upgrade() {
363                        *source.value.borrow_mut() = t_value;
364                        *source.explicitly_modified.borrow_mut() = true;
365                    }
366                }
367            }
368        });
369        new_signal.0.react_fns.borrow_mut().push(backward_react_fn);
370
371        // Register self (source) as a predecessor of new_signal (backward dependency)
372        // When new_signal changes, it propagates backward to self
373        new_signal
374            .0
375            .predecessors
376            .borrow_mut()
377            .push(WeakSignalRef::new(self));
378
379        result_new_signal
380    }
381
382    /// Combine two signals into one
383    ///
384    /// This combines two signals into a new signal that holds a tuple of their values.
385    /// Changes to either signal will propagate to the new combined signal.
386    ///
387    /// # Example
388    /// ```rust
389    /// let a = Signal::new(10);
390    /// let b = a.map(|x| x * 2);
391    /// let ab = a.combine(&b);
392    /// ab.with(|(x, y)| println!("c changed: {} + {} = {}", x, y, x + y));
393    /// a.send(5); // prints "c changed: 5 + 10 = 15"
394    /// ```
395    pub fn combine<S>(&self, another: S) -> Signal<'a, (T, S::Inner)>
396    where
397        S: Liftable<'a>,
398        S::Inner: 'a,
399        T: 'a,
400    {
401        self.combine_ref::<S, WeakRefStrategy>(another)
402    }
403
404    /// Combine two signals into one with strong references
405    ///
406    /// This combines two signals into a new signal that holds a tuple of their values.
407    /// Changes to either signal will propagate to the new combined signal.
408    /// This combination uses strong references.
409    ///
410    /// # Example
411    /// ```rust
412    /// let a = Signal::new(10);
413    /// let b = a.map(|x| x * 2);
414    /// a.and(&b).with(|(x, y)| println!("c changed: {} + {} = {}", x, y, x + y));
415    /// a.send(5); // prints "c changed: 5 + 10 = 15"
416    /// ```
417    pub fn and<S>(&self, another: S) -> Signal<'a, (T, S::Inner)>
418    where
419        S: Liftable<'a>,
420        S::Inner: 'a,
421        T: 'a,
422    {
423        self.combine_ref::<S, StrongRefStrategy>(another)
424    }
425
426    fn combine_ref<S: Liftable<'a>, Strat: RefStrategy<'a>>(
427        &self,
428        another: S,
429    ) -> Signal<'a, (T, S::Inner)>
430    where
431        S::Inner: 'a,
432        T: 'a,
433    {
434        let another = another.as_ref();
435
436        // Take values temporarily, create signal, restore values
437        let temp_val_0 = Self::take_value(&self.0.value);
438        let temp_val_1 = Self::take_value(&another.0.value);
439        let new_signal = Signal::new((temp_val_0, temp_val_1));
440        std::mem::swap(
441            &mut *self.0.value.borrow_mut(),
442            &mut new_signal.0.value.borrow_mut().0,
443        );
444        std::mem::swap(
445            &mut *another.0.value.borrow_mut(),
446            &mut new_signal.0.value.borrow_mut().1,
447        );
448
449        let result_new_signal = new_signal.clone();
450
451        // Register reaction for first source
452        let new_signal_ref = Strat::new_ref(&new_signal.0);
453        let self_ref = Strat::new_ref(&self.0);
454        let react_fn_self = Box::new(move || {
455            if let (Some(new_sig), Some(src)) =
456                (Strat::upgrade(&new_signal_ref), Strat::upgrade(&self_ref))
457            {
458                if !*new_sig.explicitly_modified.borrow() {
459                    std::mem::swap(
460                        &mut *src.value.borrow_mut(),
461                        &mut new_sig.value.borrow_mut().0,
462                    );
463                }
464            }
465        });
466        self.0.react_fns.borrow_mut().push(react_fn_self);
467        self.0
468            .successors
469            .borrow_mut()
470            .push(WeakSignalRef::new(&result_new_signal));
471
472        // Register reaction for second source
473        let new_signal_ref_2 = Strat::new_ref(&new_signal.0);
474        let another_ref = Strat::new_ref(&another.0);
475        let react_fn_another = Box::new(move || {
476            if let (Some(new_sig), Some(src)) = (
477                Strat::upgrade(&new_signal_ref_2),
478                Strat::upgrade(&another_ref),
479            ) {
480                if !*new_sig.explicitly_modified.borrow() {
481                    std::mem::swap(
482                        &mut *src.value.borrow_mut(),
483                        &mut new_sig.value.borrow_mut().1,
484                    );
485                }
486            }
487        });
488        another.0.react_fns.borrow_mut().push(react_fn_another);
489        another
490            .0
491            .successors
492            .borrow_mut()
493            .push(WeakSignalRef::new(&result_new_signal));
494
495        result_new_signal
496    }
497
498    /// Extend the signal with a vector of signals
499    ///
500    /// This creates a new signal that depends on the current signal and the provided signals.
501    /// Changes to any of the source signals will propagate to the new signal.
502    ///
503    /// # Example
504    /// ```rust
505    /// let a = Signal::new(1);
506    /// let b = Signal::new(2);
507    /// let c = Signal::new(3);
508    /// let d = a.extend(vec![b, c]);
509    /// d.with(|values| println!("d changed: {:?}", values));
510    /// a.send(10); // prints "d changed: [10, 2, 3]"
511    /// (b.send(20), c.send(30)); // prints "d changed: [10, 20, 30]"
512    /// ```
513    pub fn extend<S>(&self, others: impl IntoIterator<Item = S>) -> Signal<'a, Vec<T>>
514    where
515        S: Liftable<'a, Inner = T>,
516        T: 'a,
517    {
518        self.extend_ref::<S, WeakRefStrategy>(others)
519    }
520
521    /// Extend the signal with a vector of signals with strong references
522    ///
523    /// This creates a new signal that depends on the current signal and the provided signals.
524    /// Changes to any of the source signals will propagate to the new signal.
525    /// It uses strong references.
526    ///
527    /// # Example
528    /// ```rust
529    /// let a = Signal::new(1);
530    /// let b = Signal::new(2);
531    /// let c = Signal::new(3);
532    /// a.follow(vec![b, c]).with(|values| println!("d changed: {:?}", values));
533    /// a.send(10); // prints "d changed: [10, 2, 3]"
534    /// (b.send(20), c.send(30)); // prints "d changed: [10, 20, 30]"
535    /// ```
536    pub fn follow<S>(&self, others: impl IntoIterator<Item = S>) -> Signal<'a, Vec<T>>
537    where
538        S: Liftable<'a, Inner = T>,
539        T: 'a,
540    {
541        self.extend_ref::<S, StrongRefStrategy>(others)
542    }
543
544    fn extend_ref<S, Strat: RefStrategy<'a>>(
545        &self,
546        others: impl IntoIterator<Item = S>,
547    ) -> Signal<'a, Vec<T>>
548    where
549        S: Liftable<'a, Inner = T>,
550        T: 'a,
551    {
552        let others_signals: Vec<Signal<'a, T>> =
553            others.into_iter().map(|s| s.as_ref().clone()).collect();
554
555        // Collect values using take_value helper - no cloning!
556        let all_signals: Vec<&Signal<'a, T>> =
557            iter::once(self).chain(others_signals.iter()).collect();
558
559        let temp_values: Vec<T> = all_signals
560            .iter()
561            .map(|s| Self::take_value(&s.0.value))
562            .collect();
563        let new_signal: Signal<'a, Vec<T>> = Signal::new(temp_values);
564
565        // Restore original values by swapping back
566        for (index, signal) in all_signals.iter().enumerate() {
567            std::mem::swap(
568                &mut *signal.0.value.borrow_mut(),
569                &mut new_signal.0.value.borrow_mut()[index],
570            );
571        }
572
573        let result_new_signal = new_signal.clone();
574
575        iter::once(self)
576            .chain(others_signals.iter())
577            .enumerate()
578            .for_each(|(index, signal)| {
579                let new_signal_ref = Strat::new_ref(&new_signal.0);
580                let source_ref = Strat::new_ref(&signal.0);
581
582                let react_fn = Box::new(move || {
583                    if let Some(new_sig) = Strat::upgrade(&new_signal_ref) {
584                        if !*new_sig.explicitly_modified.borrow() {
585                            if let Some(src) = Strat::upgrade(&source_ref) {
586                                // Swap values instead of cloning (during reaction only)
587                                std::mem::swap(
588                                    &mut new_sig.value.borrow_mut()[index],
589                                    &mut *src.value.borrow_mut(),
590                                );
591                            }
592                        }
593                    }
594                });
595
596                signal.0.react_fns.borrow_mut().push(react_fn);
597                signal
598                    .0
599                    .successors
600                    .borrow_mut()
601                    .push(WeakSignalRef::new(&new_signal));
602            });
603
604        result_new_signal
605    }
606
607    /// Let this signal depend on another signal
608    ///
609    /// This synchronizes the value of this signal with the value of the dependency signal.
610    /// Whenever the dependency signal changes, this signal will be updated to match its value.
611    ///
612    /// The returned signal is exactly the argument `dependency`. You can break the dependency chain
613    /// by dropping the returned signal if `dependency` is weakly referenced.
614    ///
615    /// # Example
616    /// ```rust
617    /// let a = Signal::new(1);
618    /// let mut b = Signal::new(2);
619    /// b = a.depend(b);
620    /// a.with(|v| println!("a changed: {}", v));
621    /// b.send(3); // prints "a changed: 3"
622    /// ```
623    ///
624    /// The example above is analogous to:
625    /// ```rust
626    /// let a = Signal::new(1);
627    /// let b = a.map(|v| *v);
628    /// b.with(|v| println!("b changed: {}", v));
629    /// a.send(3); // prints "b changed: 3"
630    /// ```
631    pub fn depend(&self, dependency: Signal<'a, T>) -> Signal<'a, T>
632    where
633        T: Clone,
634    {
635        let self_weak = Rc::downgrade(&self.0);
636        let dependency_weak = Rc::downgrade(&dependency.0);
637
638        let react_fn = Box::new(move || {
639            if let Some(dep) = dependency_weak.upgrade() {
640                if let Some(target) = self_weak.upgrade() {
641                    if !*target.explicitly_modified.borrow() {
642                        // Swap values instead of cloning (during reaction only)
643                        std::mem::swap(
644                            &mut *target.value.borrow_mut(),
645                            &mut *dep.value.borrow_mut(),
646                        );
647                    }
648                }
649            }
650        });
651
652        dependency.0.react_fns.borrow_mut().push(react_fn);
653        dependency
654            .0
655            .successors
656            .borrow_mut()
657            .push(WeakSignalRef::new(self));
658        dependency
659    }
660
661    pub(crate) fn modify(&self, f: impl FnOnce(&mut T)) {
662        let mut value = self.0.value.borrow_mut();
663        f(&mut value);
664    }
665
666    fn mark_dirty(&self) {
667        *self.0.dirty.borrow_mut() += 1;
668    }
669
670    fn collect_and_iterate<F>(&self, refs: &RefCell<Vec<WeakSignalRef<'a>>>, mut callback: F)
671    where
672        F: FnMut(&dyn SignalExt<'a>),
673    {
674        refs.borrow_mut().retain(|s| s.is_alive());
675        for s in refs.borrow().iter() {
676            if let Some(signal) = s.upgrade() {
677                callback(&*signal);
678            }
679        }
680    }
681
682    fn collect_guards(&self, result: &mut Vec<SignalGuardInner<'a>>) {
683        self.mark_dirty();
684        result.push(SignalGuardInner(self.clone_box()));
685        self.collect_and_iterate(&self.0.successors, |signal| {
686            signal.collect_guards_recursive(result);
687        });
688        self.collect_and_iterate(&self.0.predecessors, |signal| {
689            signal.collect_predecessors_recursive(result);
690        });
691    }
692
693    /// Lift an array of liftable items into a signal of an array
694    ///
695    /// This creates a new signal that depends on the provided liftable items.
696    /// Changes to any of the source signals will propagate to the new signal.
697    ///
698    /// # Example
699    /// ```rust
700    /// let a = Signal::new(1);
701    /// let b = Signal::new(2);
702    /// let c = Signal::new(3);
703    /// let abc = Signal::lift_from_array([a, b, c]);
704    /// abc.with(|values| println!("abc changed: {:?}", values));
705    /// (a.send(10), b.send(20), c.send(30)); // prints "abc changed: [10, 20, 30]"
706    /// ```
707    pub fn lift_from_array<S, const N: usize>(items: [S; N]) -> Signal<'a, [S::Inner; N]>
708    where
709        S: Liftable<'a>,
710        S::Inner: 'a,
711    {
712        let signals: [Signal<'a, S::Inner>; N] = std::array::from_fn(|i| items[i].as_ref().clone());
713
714        // Take values using helper - no cloning!
715        let initial: [S::Inner; N] = std::array::from_fn(|i| Self::take_value(&signals[i].0.value));
716        let new_signal: Signal<'a, [S::Inner; N]> = Signal::new(initial);
717
718        // Restore original values by swapping back
719        for (index, signal) in signals.iter().enumerate() {
720            std::mem::swap(
721                &mut *signal.0.value.borrow_mut(),
722                &mut new_signal.0.value.borrow_mut()[index],
723            );
724        }
725
726        let result_new_signal = new_signal.clone();
727
728        for (index, signal) in signals.iter().enumerate() {
729            let new_signal_weak = Rc::downgrade(&new_signal.0);
730            let source_for_closure = Rc::downgrade(&signal.0);
731
732            let react_fn = Box::new(move || {
733                if let Some(new_sig) = new_signal_weak.upgrade() {
734                    if !*new_sig.explicitly_modified.borrow() {
735                        if let Some(source) = source_for_closure.upgrade() {
736                            // Swap instead of cloning (during reaction only)
737                            std::mem::swap(
738                                &mut new_sig.value.borrow_mut()[index],
739                                &mut *source.value.borrow_mut(),
740                            );
741                        }
742                    }
743                }
744            });
745
746            signal.0.react_fns.borrow_mut().push(react_fn);
747            signal
748                .0
749                .successors
750                .borrow_mut()
751                .push(WeakSignalRef::new(&new_signal));
752        }
753
754        result_new_signal
755    }
756}
757
758impl<'a, T: 'a> SignalExt<'a> for Signal<'a, T> {
759    fn react(&self) {
760        self.0.react_fns.borrow().iter().for_each(|react_fn| {
761            react_fn();
762        });
763    }
764    fn guard(&self) -> SignalGuard<'a> {
765        let mut result = vec![];
766        self.collect_guards(&mut result);
767        SignalGuard(result)
768    }
769    fn clone_box(&self) -> Box<dyn SignalExt<'a> + 'a> {
770        Box::new(Signal(Rc::clone(&self.0)))
771    }
772    fn decrease_dirty(&self) {
773        *self.0.dirty.borrow_mut() -= 1;
774    }
775    fn get_dirty(&self) -> isize {
776        *self.0.dirty.borrow()
777    }
778    fn reset_explicitly_modified(&self) {
779        *self.0.explicitly_modified.borrow_mut() = false;
780    }
781    fn collect_guards_recursive(&self, result: &mut Vec<SignalGuardInner<'a>>) {
782        self.mark_dirty();
783        result.push(SignalGuardInner(self.clone_box()));
784        self.collect_and_iterate(&self.0.successors, |signal| {
785            signal.collect_guards_recursive(result);
786        });
787    }
788    fn collect_predecessors_recursive(&self, result: &mut Vec<SignalGuardInner<'a>>) {
789        self.mark_dirty();
790        result.push(SignalGuardInner(self.clone_box()));
791        // Collect predecessors last so they drop last (react last)
792        self.collect_and_iterate(&self.0.predecessors, |signal| {
793            signal.collect_predecessors_recursive(result);
794        });
795    }
796}
797
798impl<T> Clone for Signal<'_, T> {
799    fn clone(&self) -> Self {
800        Self(self.0.clone())
801    }
802}
803
804impl<'a, T> AsRef<Signal<'a, T>> for Signal<'a, T> {
805    fn as_ref(&self) -> &Signal<'a, T> {
806        self
807    }
808}
809
810#[cfg(test)]
811mod tests {
812
813    use crate::api::LiftInto;
814
815    use super::*;
816
817    #[test]
818    fn test_signal() {
819        let a = Signal::new(0);
820        let _a = a.map(|x| println!("a changed: {}", x));
821        (a.send(100), a.send(5));
822    }
823
824    #[test]
825    fn test_signal1() {
826        let a = Signal::new(0);
827        let b = a.map(|x| x * 2);
828        let _b = b.map(|x| println!("b changed: {}", x));
829        drop(b);
830        a.send(100);
831    }
832
833    #[test]
834    fn test_signal2() {
835        let a = Signal::new(0);
836        let b = a.map(|x| x * 2);
837        let ab = a.combine(&b);
838        let _ab = ab.map(|(x, y)| println!("c changed: {} + {} = {}", x, y, x + y));
839        (a.send(5), a.send(100));
840    }
841
842    #[test]
843    fn test_signal3() {
844        let a = Signal::new(0);
845        let b = a.map(|x| x * 2);
846        let ab = (&a, &b).lift();
847        let _ab = ab.map(|(x, y)| println!("c changed: {} + {} = {}", x, y, x + y));
848        (a.send(5), b.send(100));
849    }
850
851    #[test]
852    fn test_signal4() {
853        let a = Signal::new(0);
854        let b = Signal::new(10);
855        let c = Signal::new(20);
856        let abc = [&a, &b, &c].lift();
857        let _abc =
858            abc.map(|[x, y, z]| println!("d changed: {} + {} + {} = {}", x, y, z, x + y + z));
859        let d = Signal::new(0);
860        let abcd = abc.combine(&d);
861        let _abcd = abcd.map(|numbers| {
862            println!(
863                "e changed: {} + {} + {} + {} = {}",
864                numbers.0[0],
865                numbers.0[1],
866                numbers.0[2],
867                numbers.1,
868                numbers.0.iter().sum::<i32>() + numbers.1
869            )
870        });
871        (a.send(5), b.send(15), c.send(25), abc.send([2, 3, 4]));
872    }
873
874    #[test]
875    fn test_signal5() {
876        let result = Signal::new(42);
877        let source1 = result.contramap(|x| x + 1);
878        let source2 = source1.contramap(|x| x * 2);
879
880        let _observer_1 = result.map(|x| println!("result changed: {}", x));
881        let _observer_2 = source1.map(|x| println!("source1 changed: {}", x));
882        let _observer_3 = source2.map(|x| println!("source2 changed: {}", x));
883
884        println!("--- Sending to source1 ---");
885        source1.send(100);
886        println!("--- Sending to source2 ---");
887        source2.send(200);
888        println!("--- Sending to source1 and source2 ---");
889        (source1.send(300), source2.send(400));
890    }
891
892    #[test]
893    fn test_promap_forward() {
894        let source = Signal::new(10);
895        let derived = source.promap(|x| x * 2, |y| y / 2);
896
897        let _ = derived.map(|x| println!("derived changed: {}", x));
898        source.send(5);
899    }
900
901    #[test]
902    fn test_promap_backward() {
903        let source = Signal::new(10);
904        let derived = source.promap(|x| x * 2, |y| y / 2);
905
906        let _ = source.map(|x| println!("source changed: {}", x));
907        let _ = derived.map(|x| println!("derived changed: {}", x));
908        derived.send(50);
909    }
910
911    #[test]
912    fn test_promap_bidirectional() {
913        let a = Signal::new(10);
914        let b = a.promap(|x| x * 2, |y| y / 2);
915        let c = b.promap(|x| x + 3, |y| y - 3);
916
917        let _observer_a = a.map(|x| println!("a changed: {}", x));
918        let _observer_b = b.map(|x| println!("b changed: {}", x));
919        let _observer_c = c.map(|x| println!("c changed: {}", x));
920
921        println!("--- Sending to a ---");
922        a.send(5);
923        println!("--- Sending to c ---");
924        c.send(13);
925        println!("--- Sending to b ---");
926        b.send(10);
927        println!("--- Sending to a and c ---");
928        a.send(20).and(c.send(50));
929        println!("--- Sending to b and c ---");
930        (b.send(30), c.send(60));
931    }
932
933    #[test]
934    fn test_high_order_signal() {
935        let source = Signal::new(0);
936        let derived = source.map(|x| Signal::new(x + 1));
937        let _ = derived.map(|s| s.send(233));
938        let _ = derived.map(|s| s.map(|x| println!("derived changed: {}", x)));
939        source.send(5);
940    }
941
942    #[test]
943    fn test_depend() {
944        let a = Signal::new(10);
945        let b = Signal::new(10);
946        let c = Signal::new(10);
947
948        let _observer_a = a.map(|x| println!("a changed: {}", x));
949        let _observer_b = b.map(|x| println!("b changed: {}", x));
950        let _observer_c = c.map(|x| println!("c changed: {}", x));
951
952        c.depend(b.with(|x| x * 2));
953        b.depend(a.clone());
954
955        a.send(42);
956    }
957
958    #[test]
959    fn test_depend2() {
960        let a = Signal::new(10);
961        let b = a.map(|x| *x);
962        let c = b.map(|x| *x);
963
964        let _observer_a = a.map(|x| println!("a changed: {}", x));
965        let _observer_b = b.map(|x| println!("b changed: {}", x));
966        let _observer_c = c.map(|x| println!("c changed: {}", x));
967
968        (a.send(42), b.send(88));
969    }
970}