@@ -5,17 +5,34 @@ use std::{
55
66use crate :: { IEffect , Observable , call_stack} ;
77
8+ /// A reactive signal that holds a value, tracks dependencies, and triggers effects.
9+ ///
10+ /// `Signal<T>` behaves similarly to a traditional "Property" (getter/setter),
11+ /// but on top of that, it automatically tracks which reactive computations
12+ /// or effects access it. When its value changes, all dependent effects
13+ /// are automatically re-run.
14+ ///
15+ /// In short:
16+ /// - Like a Property: provides `get()` and `set()` for accessing and updating the value.
17+ /// - Adds tracking: automatically records dependencies when read inside reactive contexts,
18+ /// and automatically triggers dependent `Effect`s when updated.
19+ ///
20+ /// # Type Parameters
21+ ///
22+ /// - `T`: The type of the value stored in the signal. Must implement `Eq + Default`.
823pub struct Signal < T > {
924 value : RefCell < T > ,
1025 dependents : RefCell < Vec < & ' static dyn Observable > > ,
1126 effects : RefCell < Vec < Weak < dyn IEffect > > > ,
1227}
1328
1429impl < T > Signal < T > {
30+ /// Invalidates all dependent observables.
1531 fn invalidate ( & self ) {
1632 self . dependents . borrow ( ) . iter ( ) . for_each ( |d| d. invalidate ( ) ) ;
1733 }
1834
35+ /// Runs all dependent effects.
1936 fn flush_effects ( & self ) {
2037 self . effects . borrow_mut ( ) . retain ( |w| {
2138 if let Some ( e) = w. upgrade ( ) {
@@ -37,6 +54,21 @@ impl<T> Signal<T> {
3754 self . invalidate ( )
3855 }
3956
57+ /// Creates a new `Signal` with the given initial value.
58+ ///
59+ /// If `None` is provided, `T::default()` is used.
60+ ///
61+ /// # Examples
62+ ///
63+ /// ```
64+ /// use reactive_cache::Signal;
65+ ///
66+ /// let signal = Signal::new(Some(10));
67+ /// assert_eq!(*signal.get(), 10);
68+ ///
69+ /// let default_signal: Signal<i32> = Signal::new(None);
70+ /// assert_eq!(*default_signal.get(), 0);
71+ /// ```
4072 pub fn new ( value : Option < T > ) -> Self
4173 where
4274 T : Default ,
@@ -48,7 +80,18 @@ impl<T> Signal<T> {
4880 }
4981 }
5082
83+ /// Gets a reference to the current value, tracking dependencies and effects if inside a reactive context.
84+ ///
85+ /// # Examples
86+ ///
87+ /// ```
88+ /// use reactive_cache::Signal;
89+ ///
90+ /// let signal = Signal::new(Some(42));
91+ /// assert_eq!(*signal.get(), 42);
92+ /// ```
5193 pub fn get ( & self ) -> Ref < ' _ , T > {
94+ // Track observables in the call stack
5295 if let Some ( last) = call_stack:: last ( )
5396 && !self
5497 . dependents
@@ -59,6 +102,7 @@ impl<T> Signal<T> {
59102 self . dependents . borrow_mut ( ) . push ( * last) ;
60103 }
61104
105+ // Track effects in the call stack
62106 if let Some ( e) = call_stack:: creating_effect_peak ( )
63107 && !self . effects . borrow ( ) . iter ( ) . any ( |w| Weak :: ptr_eq ( w, & e) )
64108 {
@@ -68,6 +112,22 @@ impl<T> Signal<T> {
68112 self . value . borrow ( )
69113 }
70114
115+ /// Sets the value of the signal.
116+ ///
117+ /// Returns `true` if the value changed and dependent effects were triggered.
118+ ///
119+ /// # Examples
120+ ///
121+ /// ```
122+ /// use reactive_cache::Signal;
123+ ///
124+ /// let signal = Signal::new(Some(5));
125+ /// assert_eq!(signal.set(10), true);
126+ /// assert_eq!(*signal.get(), 10);
127+ ///
128+ /// // Setting to the same value returns false
129+ /// assert_eq!(signal.set(10), false);
130+ /// ```
71131 pub fn set ( & self , value : T ) -> bool
72132 where
73133 T : Eq ,
0 commit comments