sycamore_reactive/
signals.rs

1//! Reactive signals.
2
3use std::cell::{Ref, RefMut};
4use std::fmt;
5use std::fmt::Formatter;
6use std::hash::Hash;
7use std::marker::PhantomData;
8use std::ops::{AddAssign, Deref, DivAssign, MulAssign, RemAssign, SubAssign};
9
10use slotmap::Key;
11use smallvec::SmallVec;
12
13use crate::*;
14
15/// A read-only reactive value.
16///
17/// Unlike the difference between Rust's shared and mutable-references (`&T` and `&mut`), the
18/// underlying data is not immutable. The data can be updated with the corresponding [`Signal`]
19/// (which has mutable access) and will show up in the `ReadSignal` as well.
20///
21/// A `ReadSignal` can be simply obtained by dereferencing a [`Signal`]. In fact, every [`Signal`]
22/// is a `ReadSignal` with additional write abilities!
23///
24/// # Example
25/// ```
26/// # use sycamore_reactive::*;
27/// # create_root(|| {
28/// let signal: Signal<i32> = create_signal(123);
29/// let read_signal: ReadSignal<i32> = *signal;
30/// assert_eq!(read_signal.get(), 123);
31/// signal.set(456);
32/// assert_eq!(read_signal.get(), 456);
33/// // read_signal.set(789); // <-- This is not allowed!
34/// # });
35/// ```
36///
37/// See [`create_signal`] for more information.
38pub struct ReadSignal<T: 'static> {
39    pub(crate) id: NodeId,
40    root: &'static Root,
41    /// Keep track of where the signal was created for diagnostics.
42    /// This is also stored in the Node but we want to have access to this when accessing a
43    /// disposed node so we store it here as well.
44    #[cfg(debug_assertions)]
45    created_at: &'static std::panic::Location<'static>,
46    _phantom: PhantomData<T>,
47}
48
49/// A reactive value that can be read and written to.
50///
51/// This is the writable version of [`ReadSignal`].
52///
53/// See [`create_signal`] for more information.
54pub struct Signal<T: 'static>(pub(crate) ReadSignal<T>);
55
56/// Create a new [`Signal`].
57///
58/// Signals are reactive atoms, pieces of state that can be read and written to and which will
59/// automatically update anything which depend on them.
60///
61/// # Usage
62/// The simplest way to use a signal is by using [`.get()`](ReadSignal::get) and
63/// [`.set(...)`](Signal::set). However, this only works if the value implements [`Copy`]. If
64/// we wanted to store something that doesn't implement [`Copy`] but implements [`Clone`] instead,
65/// say a [`String`], we can use [`.get_clone()`](ReadSignal::get_clone) which will automatically
66/// clone the value for us.
67///
68/// ```rust
69/// # use sycamore_reactive::*;
70/// # create_root(|| {
71/// let signal = create_signal(1);
72/// signal.get(); // Should return 1.
73/// signal.set(2);
74/// signal.get(); // Should return 2.
75/// # });
76/// ```
77///
78/// There are many other ways of getting and setting signals, such as
79/// [`.with(...)`](ReadSignal::with) and [`.update(...)`](Signal::update) which can access the
80/// signal even if it does not implement [`Clone`] or if you simply don't want to pay the
81/// performance overhead of cloning your value everytime you read it.
82///
83/// # Reactivity
84/// What makes signals so powerful, as opposed to some other wrapper type like
85/// [`RefCell`](std::cell::RefCell) is the automatic dependency tracking. This means that accessing
86/// a signal will automatically add it as a dependency in certain contexts (such as inside a
87/// [`create_memo`](crate::create_memo)) which allows us to update related state whenever the signal
88/// is changed.
89///
90/// ```rust
91/// # use sycamore_reactive::*;
92/// # create_root(|| {
93/// let signal = create_signal(1);
94/// // Note that we are accessing signal inside a closure in the line below. This will cause it to
95/// // be automatically tracked and update our double value whenever signal is changed.
96/// let double = create_memo(move || signal.get() * 2);
97/// double.get(); // Should return 2.
98/// signal.set(2);
99/// double.get(); // Should return 4. Notice how this value was updated automatically when we
100///               // modified signal. This way, we can rest assured that all our state will be
101///               // consistent at all times!
102/// # });
103/// ```
104///
105/// # Ownership
106/// Signals are always associated with a reactive node. This is what performs the memory management
107/// for the actual value of the signal. What is returned from this function is just a
108/// handle/reference to the signal allocted in the reactive node. This allows us to freely copy this
109/// handle around and use it in closures and event handlers without worrying about ownership of the
110/// signal.
111///
112/// This is why in the above example, we could access `signal` even after it was moved in to the
113/// closure of the `create_memo`.
114#[cfg_attr(debug_assertions, track_caller)]
115pub fn create_signal<T>(value: T) -> Signal<T> {
116    let signal = create_empty_signal();
117    signal.get_mut().value = Some(Box::new(value));
118    signal
119}
120
121/// Creates a new [`Signal`] with the `value` field set to `None`.
122#[cfg_attr(debug_assertions, track_caller)]
123pub(crate) fn create_empty_signal<T>() -> Signal<T> {
124    let root = Root::global();
125    let id = root.nodes.borrow_mut().insert(ReactiveNode {
126        value: None,
127        callback: None,
128        children: Vec::new(),
129        parent: root.current_node.get(),
130        dependents: Vec::new(),
131        dependencies: SmallVec::new(),
132        cleanups: Vec::new(),
133        context: Vec::new(),
134        state: NodeState::Clean,
135        mark: Mark::None,
136        #[cfg(debug_assertions)]
137        created_at: std::panic::Location::caller(),
138    });
139    // Add the signal to the parent's `children` list.
140    let current_node = root.current_node.get();
141    if !current_node.is_null() {
142        root.nodes.borrow_mut()[current_node].children.push(id);
143    }
144
145    Signal(ReadSignal {
146        id,
147        root,
148        #[cfg(debug_assertions)]
149        created_at: std::panic::Location::caller(),
150        _phantom: PhantomData,
151    })
152}
153
154impl<T> ReadSignal<T> {
155    /// Get a immutable reference to the underlying node.
156    #[cfg_attr(debug_assertions, track_caller)]
157    pub(crate) fn get_ref(self) -> Ref<'static, ReactiveNode> {
158        Ref::map(self.root.nodes.borrow(), |nodes| match nodes.get(self.id) {
159            Some(node) => node,
160            None => panic!("{}", self.get_disposed_panic_message()),
161        })
162    }
163
164    /// Get a mutable reference to the underlying node.
165    #[cfg_attr(debug_assertions, track_caller)]
166    pub(crate) fn get_mut(self) -> RefMut<'static, ReactiveNode> {
167        RefMut::map(self.root.nodes.borrow_mut(), |nodes| {
168            match nodes.get_mut(self.id) {
169                Some(node) => node,
170                None => panic!("{}", self.get_disposed_panic_message()),
171            }
172        })
173    }
174
175    /// Returns `true` if the signal is still alive, i.e. has not yet been disposed.
176    pub fn is_alive(self) -> bool {
177        self.root.nodes.borrow().get(self.id).is_some()
178    }
179
180    /// Disposes the signal, i.e. frees up the memory held on by this signal. Accessing a signal
181    /// after it has been disposed immediately causes a panic.
182    pub fn dispose(self) {
183        NodeHandle(self.id, self.root).dispose();
184    }
185
186    fn get_disposed_panic_message(self) -> String {
187        #[cfg(not(debug_assertions))]
188        return "signal was disposed".to_string();
189
190        #[cfg(debug_assertions)]
191        return format!("signal was disposed. Created at {}", self.created_at);
192    }
193
194    /// Get the value of the signal without tracking it. The type must implement [`Copy`]. If this
195    /// is not the case, use [`ReadSignal::get_clone_untracked`] or [`ReadSignal::with_untracked`]
196    /// instead.
197    ///
198    /// # Example
199    /// ```
200    /// # use sycamore_reactive::*;
201    /// # create_root(|| {
202    /// let state = create_signal(0);
203    /// // Note that we have used `get_untracked` here so the signal is not actually being tracked
204    /// // by the memo.
205    /// let doubled = create_memo(move || state.get_untracked() * 2);
206    /// state.set(1);
207    /// assert_eq!(doubled.get(), 0);
208    /// # });
209    /// ```
210    #[cfg_attr(debug_assertions, track_caller)]
211    pub fn get_untracked(self) -> T
212    where
213        T: Copy,
214    {
215        self.with_untracked(|value| *value)
216    }
217
218    /// Get the value of the signal without tracking it. The type is [`Clone`]-ed automatically.
219    ///
220    /// This is the cloned equivalent of [`ReadSignal::get_untracked`].
221    #[cfg_attr(debug_assertions, track_caller)]
222    pub fn get_clone_untracked(self) -> T
223    where
224        T: Clone,
225    {
226        self.with_untracked(Clone::clone)
227    }
228
229    /// Get the value of the signal. The type must implement [`Copy`]. If this is not the case, use
230    /// [`ReadSignal::get_clone_untracked`] or [`ReadSignal::with_untracked`] instead.
231    ///
232    /// When called inside a reactive scope, the signal will be automatically tracked.
233    ///
234    /// # Example
235    /// ```
236    /// # use sycamore_reactive::*;
237    /// # create_root(|| {
238    /// let state = create_signal(0);
239    /// assert_eq!(state.get(), 0);
240    ///
241    /// state.set(1);
242    /// assert_eq!(state.get(), 1);
243    ///
244    /// // The signal is automatically tracked in the line below.
245    /// let doubled = create_memo(move || state.get());
246    /// # });
247    /// ```
248    #[cfg_attr(debug_assertions, track_caller)]
249    pub fn get(self) -> T
250    where
251        T: Copy,
252    {
253        self.track();
254        self.get_untracked()
255    }
256
257    /// Get the value of the signal. The type is [`Clone`]-ed automatically.
258    ///
259    /// When called inside a reactive scope, the signal will be automatically tracked.
260    ///
261    /// If the value implements [`Copy`], you should use [`ReadSignal::get`] instead.
262    ///
263    /// # Example
264    /// ```
265    /// # use sycamore_reactive::*;
266    /// # create_root(|| {
267    /// let greeting = create_signal("Hello".to_string());
268    /// assert_eq!(greeting.get_clone(), "Hello".to_string());
269    ///
270    /// // The signal is automatically tracked in the line below.
271    /// let hello_world = create_memo(move || format!("{} World!", greeting.get_clone()));
272    /// assert_eq!(hello_world.get_clone(), "Hello World!");
273    ///
274    /// greeting.set("Goodbye".to_string());
275    /// assert_eq!(greeting.get_clone(), "Goodbye".to_string());
276    /// assert_eq!(hello_world.get_clone(), "Goodbye World!");
277    /// # });
278    /// ```
279    #[cfg_attr(debug_assertions, track_caller)]
280    pub fn get_clone(self) -> T
281    where
282        T: Clone,
283    {
284        self.track();
285        self.get_clone_untracked()
286    }
287
288    /// Get a value from the signal without tracking it.
289    #[cfg_attr(debug_assertions, track_caller)]
290    pub fn with_untracked<U>(self, f: impl FnOnce(&T) -> U) -> U {
291        let node = self.get_ref();
292        let value = node.value.as_ref().expect("value updating");
293        let ret = f(value.downcast_ref().expect("wrong signal type"));
294        ret
295    }
296
297    /// Get a value from the signal.
298    ///
299    /// When called inside a reactive scope, the signal will be automatically tracked.
300    #[cfg_attr(debug_assertions, track_caller)]
301    pub fn with<U>(self, f: impl FnOnce(&T) -> U) -> U {
302        self.track();
303        self.with_untracked(f)
304    }
305
306    /// Creates a new [memo](create_memo) from this signal and a function. The resulting memo will
307    /// be created in the current reactive scope.
308    ///
309    /// # Example
310    /// ```
311    /// # use sycamore_reactive::*;
312    /// # create_root(|| {
313    /// let state = create_signal(0);
314    /// let doubled = state.map(|val| *val * 2);
315    /// assert_eq!(doubled.get(), 0);
316    /// state.set(1);
317    /// assert_eq!(doubled.get(), 2);
318    /// # });
319    /// ```
320    #[cfg_attr(debug_assertions, track_caller)]
321    pub fn map<U>(self, mut f: impl FnMut(&T) -> U + 'static) -> ReadSignal<U> {
322        create_memo(move || self.with(&mut f))
323    }
324
325    /// Track the signal in the current reactive scope. This is done automatically when calling
326    /// [`ReadSignal::get`] and other similar methods.
327    ///
328    /// # Example
329    /// ```
330    /// # use sycamore_reactive::*;
331    /// # create_root(|| {
332    /// let state = create_signal(0);
333    /// create_effect(move || {
334    ///     state.track(); // Track the signal without getting its value.
335    ///     println!("Yipee!");
336    /// });
337    /// state.set(1); // Prints "Yipee!"
338    /// # });
339    /// ```
340    pub fn track(self) {
341        if let Some(tracker) = &mut *self.root.tracker.borrow_mut() {
342            tracker.dependencies.push(self.id);
343        }
344    }
345}
346
347impl<T> Signal<T> {
348    /// Silently set a new value for the signal. This will not trigger any updates in dependent
349    /// signals. As such, this is generally not recommended as it can easily lead to state
350    /// inconsistencies.
351    ///
352    /// # Example
353    /// ```
354    /// # use sycamore_reactive::*;
355    /// # create_root(|| {
356    /// let state = create_signal(0);
357    /// let doubled = create_memo(move || state.get() * 2);
358    /// assert_eq!(doubled.get(), 0);
359    /// state.set_silent(1);
360    /// assert_eq!(doubled.get(), 0); // We now have inconsistent state!
361    /// # });
362    /// ```
363    #[cfg_attr(debug_assertions, track_caller)]
364    pub fn set_silent(self, new: T) {
365        self.replace_silent(new);
366    }
367
368    /// Set a new value for the signal and automatically update any dependents.
369    ///
370    /// # Example
371    /// ```
372    /// # use sycamore_reactive::*;
373    /// # create_root(|| {
374    /// let state = create_signal(0);
375    /// let doubled = create_memo(move || state.get() * 2);
376    /// assert_eq!(doubled.get(), 0);
377    /// state.set(1);
378    /// assert_eq!(doubled.get(), 2);
379    /// # });
380    /// ```
381    #[cfg_attr(debug_assertions, track_caller)]
382    pub fn set(self, new: T) {
383        self.replace(new);
384    }
385
386    /// Silently set a new value for the signal and return the previous value.
387    ///
388    /// This is the silent version of [`Signal::replace`].
389    #[cfg_attr(debug_assertions, track_caller)]
390    pub fn replace_silent(self, new: T) -> T {
391        self.update_silent(|val| std::mem::replace(val, new))
392    }
393
394    /// Set a new value for the signal and return the previous value.
395    ///
396    /// # Example
397    /// ```
398    /// # use sycamore_reactive::*;
399    /// # create_root(|| {
400    /// let state = create_signal(123);
401    /// let prev = state.replace(456);
402    /// assert_eq!(state.get(), 456);
403    /// assert_eq!(prev, 123);
404    /// # });
405    /// ```
406    #[cfg_attr(debug_assertions, track_caller)]
407    pub fn replace(self, new: T) -> T {
408        self.update(|val| std::mem::replace(val, new))
409    }
410
411    /// Silently gets the value of the signal and sets the new value to the default value.
412    ///
413    /// This is the silent version of [`Signal::take`].
414    #[cfg_attr(debug_assertions, track_caller)]
415    pub fn take_silent(self) -> T
416    where
417        T: Default,
418    {
419        self.replace_silent(T::default())
420    }
421
422    /// Gets the value of the signal and sets the new value to the default value.
423    ///
424    /// # Example
425    /// ```
426    /// # use sycamore_reactive::*;
427    /// # create_root(|| {
428    /// let state = create_signal(Some(123));
429    /// let prev = state.take();
430    /// assert_eq!(state.get(), None);
431    /// assert_eq!(prev, Some(123));
432    /// # });
433    /// ```
434    #[cfg_attr(debug_assertions, track_caller)]
435    pub fn take(self) -> T
436    where
437        T: Default,
438    {
439        self.replace(T::default())
440    }
441
442    /// Update the value of the signal silently. This will not trigger any updates in dependent
443    /// signals. As such, this is generally not recommended as it can easily lead to state
444    /// inconsistencies.
445    ///
446    /// This is the silent version of [`Signal::update`].
447    #[cfg_attr(debug_assertions, track_caller)]
448    pub fn update_silent<U>(self, f: impl FnOnce(&mut T) -> U) -> U {
449        let mut value = self.get_mut().value.take().expect("value updating");
450        let ret = f(value.downcast_mut().expect("wrong signal type"));
451        self.get_mut().value = Some(value);
452        ret
453    }
454
455    /// Update the value of the signal and automatically update any dependents.
456    ///
457    /// Using this has the advantage of not needing to clone the value when updating it, especially
458    /// with types that do not implement `Copy` where cloning can be expensive, or for types that
459    /// do not implement `Clone` at all.
460    ///
461    /// # Example
462    /// ```
463    /// # use sycamore_reactive::*;
464    /// # create_root(|| {
465    /// let state = create_signal("Hello".to_string());
466    /// state.update(|val| val.push_str(" Sycamore!"));
467    /// assert_eq!(state.get_clone(), "Hello Sycamore!");
468    /// # });
469    /// ```
470    #[cfg_attr(debug_assertions, track_caller)]
471    pub fn update<U>(self, f: impl FnOnce(&mut T) -> U) -> U {
472        let ret = self.update_silent(f);
473        self.0.root.propagate_updates(self.0.id);
474        ret
475    }
476
477    /// Use a function to produce a new value and sets the value silently.
478    ///
479    /// This is the silent version of [`Signal::set_fn`].
480    #[cfg_attr(debug_assertions, track_caller)]
481    pub fn set_fn_silent(self, f: impl FnOnce(&T) -> T) {
482        self.update_silent(move |val| *val = f(val));
483    }
484
485    /// Use a function to produce a new value and sets the value.
486    ///
487    /// # Example
488    /// ```
489    /// # use sycamore_reactive::*;
490    /// # create_root(|| {
491    /// let state = create_signal(123);
492    /// state.set_fn(|val| *val + 1);
493    /// assert_eq!(state.get(), 124);
494    /// # });
495    /// ```
496    #[cfg_attr(debug_assertions, track_caller)]
497    pub fn set_fn(self, f: impl FnOnce(&T) -> T) {
498        self.update(move |val| *val = f(val));
499    }
500
501    /// Split the signal into a reader/writter pair.
502    ///
503    /// # Example
504    /// ```
505    /// # use sycamore_reactive::*;
506    /// # create_root(|| {
507    /// let (read_signal, mut write_signal) = create_signal(0).split();
508    /// assert_eq!(read_signal.get(), 0);
509    /// write_signal(1);
510    /// assert_eq!(read_signal.get(), 1);
511    /// # });
512    /// ```
513    pub fn split(self) -> (ReadSignal<T>, impl Fn(T) -> T) {
514        (*self, move |value| self.replace(value))
515    }
516}
517
518/// We manually implement `Clone` + `Copy` for `Signal` so that we don't get extra bounds on `T`.
519impl<T> Clone for ReadSignal<T> {
520    fn clone(&self) -> Self {
521        *self
522    }
523}
524impl<T> Copy for ReadSignal<T> {}
525
526impl<T> Clone for Signal<T> {
527    fn clone(&self) -> Self {
528        *self
529    }
530}
531impl<T> Copy for Signal<T> {}
532
533// Implement `Default` for `ReadSignal` and `Signal`.
534impl<T: Default> Default for ReadSignal<T> {
535    fn default() -> Self {
536        *create_signal(Default::default())
537    }
538}
539impl<T: Default> Default for Signal<T> {
540    fn default() -> Self {
541        create_signal(Default::default())
542    }
543}
544
545// Forward `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Hash` from inner type.
546impl<T: PartialEq> PartialEq for ReadSignal<T> {
547    fn eq(&self, other: &Self) -> bool {
548        self.with(|value| other.with(|other| value == other))
549    }
550}
551impl<T: Eq> Eq for ReadSignal<T> {}
552impl<T: PartialOrd> PartialOrd for ReadSignal<T> {
553    #[cfg_attr(debug_assertions, track_caller)]
554    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
555        self.with(|value| other.with(|other| value.partial_cmp(other)))
556    }
557}
558impl<T: Ord> Ord for ReadSignal<T> {
559    #[cfg_attr(debug_assertions, track_caller)]
560    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
561        self.with(|value| other.with(|other| value.cmp(other)))
562    }
563}
564impl<T: Hash> Hash for ReadSignal<T> {
565    #[cfg_attr(debug_assertions, track_caller)]
566    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
567        self.with(|value| value.hash(state))
568    }
569}
570
571impl<T: PartialEq> PartialEq for Signal<T> {
572    #[cfg_attr(debug_assertions, track_caller)]
573    fn eq(&self, other: &Self) -> bool {
574        self.with(|value| other.with(|other| value == other))
575    }
576}
577impl<T: Eq> Eq for Signal<T> {}
578impl<T: PartialOrd> PartialOrd for Signal<T> {
579    #[cfg_attr(debug_assertions, track_caller)]
580    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
581        self.with(|value| other.with(|other| value.partial_cmp(other)))
582    }
583}
584impl<T: Ord> Ord for Signal<T> {
585    #[cfg_attr(debug_assertions, track_caller)]
586    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
587        self.with(|value| other.with(|other| value.cmp(other)))
588    }
589}
590impl<T: Hash> Hash for Signal<T> {
591    #[cfg_attr(debug_assertions, track_caller)]
592    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
593        self.with(|value| value.hash(state))
594    }
595}
596
597impl<T> Deref for Signal<T> {
598    type Target = ReadSignal<T>;
599
600    fn deref(&self) -> &Self::Target {
601        &self.0
602    }
603}
604
605// Formatting implementations for `ReadSignal` and `Signal`.
606impl<T: fmt::Debug> fmt::Debug for ReadSignal<T> {
607    #[cfg_attr(debug_assertions, track_caller)]
608    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
609        self.with(|value| value.fmt(f))
610    }
611}
612impl<T: fmt::Debug> fmt::Debug for Signal<T> {
613    #[cfg_attr(debug_assertions, track_caller)]
614    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
615        self.with(|value| value.fmt(f))
616    }
617}
618
619impl<T: fmt::Display> fmt::Display for ReadSignal<T> {
620    #[cfg_attr(debug_assertions, track_caller)]
621    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
622        self.with(|value| value.fmt(f))
623    }
624}
625impl<T: fmt::Display> fmt::Display for Signal<T> {
626    #[cfg_attr(debug_assertions, track_caller)]
627    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
628        self.with(|value| value.fmt(f))
629    }
630}
631
632// Serde implementations for `ReadSignal` and `Signal`.
633#[cfg(feature = "serde")]
634impl<T: serde::Serialize> serde::Serialize for ReadSignal<T> {
635    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
636        self.with(|value| value.serialize(serializer))
637    }
638}
639#[cfg(feature = "serde")]
640impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for ReadSignal<T> {
641    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
642        Ok(*create_signal(T::deserialize(deserializer)?))
643    }
644}
645#[cfg(feature = "serde")]
646impl<T: serde::Serialize> serde::Serialize for Signal<T> {
647    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
648        self.with(|value| value.serialize(serializer))
649    }
650}
651#[cfg(feature = "serde")]
652impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Signal<T> {
653    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
654        Ok(create_signal(T::deserialize(deserializer)?))
655    }
656}
657
658#[cfg(feature = "nightly")]
659impl<T: Copy> FnOnce<()> for ReadSignal<T> {
660    type Output = T;
661
662    extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
663        self.get()
664    }
665}
666
667impl<T: AddAssign<Rhs>, Rhs> AddAssign<Rhs> for Signal<T> {
668    fn add_assign(&mut self, rhs: Rhs) {
669        self.update(|this| *this += rhs);
670    }
671}
672impl<T: SubAssign<Rhs>, Rhs> SubAssign<Rhs> for Signal<T> {
673    fn sub_assign(&mut self, rhs: Rhs) {
674        self.update(|this| *this -= rhs);
675    }
676}
677impl<T: MulAssign<Rhs>, Rhs> MulAssign<Rhs> for Signal<T> {
678    fn mul_assign(&mut self, rhs: Rhs) {
679        self.update(|this| *this *= rhs);
680    }
681}
682impl<T: DivAssign<Rhs>, Rhs> DivAssign<Rhs> for Signal<T> {
683    fn div_assign(&mut self, rhs: Rhs) {
684        self.update(|this| *this /= rhs);
685    }
686}
687impl<T: RemAssign<Rhs>, Rhs> RemAssign<Rhs> for Signal<T> {
688    fn rem_assign(&mut self, rhs: Rhs) {
689        self.update(|this| *this %= rhs);
690    }
691}
692
693// We need to implement this again for `Signal` despite `Signal` deref-ing to `ReadSignal` since
694// we also have another implementation of `FnOnce` for `Signal`.
695#[cfg(feature = "nightly")]
696impl<T: Copy> FnOnce<()> for Signal<T> {
697    type Output = T;
698
699    extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
700        self.get()
701    }
702}
703
704#[cfg(feature = "nightly")]
705impl<T: Copy> FnOnce<(T,)> for Signal<T> {
706    type Output = T;
707
708    extern "rust-call" fn call_once(self, (val,): (T,)) -> Self::Output {
709        self.replace(val)
710    }
711}
712
713#[cfg(test)]
714mod tests {
715    use crate::*;
716
717    #[test]
718    fn signal() {
719        let _ = create_root(|| {
720            let state = create_signal(0);
721            assert_eq!(state.get(), 0);
722
723            state.set(1);
724            assert_eq!(state.get(), 1);
725
726            state.set_fn(|n| *n + 1);
727            assert_eq!(state.get(), 2);
728        });
729    }
730
731    #[test]
732    fn signal_composition() {
733        let _ = create_root(|| {
734            let state = create_signal(0);
735            let double = || state.get() * 2;
736
737            assert_eq!(double(), 0);
738            state.set(1);
739            assert_eq!(double(), 2);
740        });
741    }
742
743    #[test]
744    fn set_silent_signal() {
745        let _ = create_root(|| {
746            let state = create_signal(0);
747            let double = state.map(|&x| x * 2);
748
749            assert_eq!(double.get(), 0);
750            state.set_silent(1);
751            assert_eq!(double.get(), 0); // double value is unchanged.
752
753            state.set_fn_silent(|n| n + 1);
754            assert_eq!(double.get(), 0); // double value is unchanged.
755        });
756    }
757
758    #[test]
759    fn read_signal() {
760        let _ = create_root(|| {
761            let state = create_signal(0);
762            let readonly: ReadSignal<i32> = *state;
763
764            assert_eq!(readonly.get(), 0);
765            state.set(1);
766            assert_eq!(readonly.get(), 1);
767        });
768    }
769
770    #[test]
771    fn map_signal() {
772        let _ = create_root(|| {
773            let state = create_signal(0);
774            let double = state.map(|&x| x * 2);
775
776            assert_eq!(double.get(), 0);
777            state.set(1);
778            assert_eq!(double.get(), 2);
779        });
780    }
781
782    #[test]
783    fn take_signal() {
784        let _ = create_root(|| {
785            let state = create_signal(123);
786
787            let x = state.take();
788            assert_eq!(x, 123);
789            assert_eq!(state.get(), 0);
790        });
791    }
792
793    #[test]
794    fn take_silent_signal() {
795        let _ = create_root(|| {
796            let state = create_signal(123);
797            let double = state.map(|&x| x * 2);
798
799            // Do not trigger subscribers.
800            state.take_silent();
801            assert_eq!(state.get(), 0);
802            assert_eq!(double.get(), 246);
803        });
804    }
805
806    #[test]
807    fn signal_split() {
808        let _ = create_root(|| {
809            let (state, set_state) = create_signal(0).split();
810            assert_eq!(state.get(), 0);
811
812            set_state(1);
813            assert_eq!(state.get(), 1);
814        });
815    }
816
817    #[test]
818    fn signal_display() {
819        let _ = create_root(|| {
820            let signal = create_signal(0);
821            assert_eq!(format!("{signal}"), "0");
822            let read_signal: ReadSignal<_> = *signal;
823            assert_eq!(format!("{read_signal}"), "0");
824            let memo = create_memo(|| 0);
825            assert_eq!(format!("{memo}"), "0");
826        });
827    }
828
829    #[test]
830    fn signal_debug() {
831        let _ = create_root(|| {
832            let signal = create_signal(0);
833            assert_eq!(format!("{signal:?}"), "0");
834            let read_signal: ReadSignal<_> = *signal;
835            assert_eq!(format!("{read_signal:?}"), "0");
836            let memo = create_memo(|| 0);
837            assert_eq!(format!("{memo:?}"), "0");
838        });
839    }
840
841    #[test]
842    fn signal_add_assign_update() {
843        let _ = create_root(|| {
844            let mut signal = create_signal(0);
845            let counter = create_signal(0);
846            create_effect(move || {
847                signal.track();
848                counter.set(counter.get_untracked() + 1);
849            });
850            signal += 1;
851            signal -= 1;
852            signal *= 1;
853            signal /= 1;
854            assert_eq!(counter.get(), 5);
855        });
856    }
857
858    #[test]
859    fn signal_update() {
860        let _ = create_root(|| {
861            let signal = create_signal("Hello ".to_string());
862            let counter = create_signal(0);
863            create_effect(move || {
864                signal.track();
865                counter.set(counter.get_untracked() + 1);
866            });
867            signal.update(|value| value.push_str("World!"));
868            assert_eq!(signal.get_clone(), "Hello World!");
869            assert_eq!(counter.get(), 2);
870        });
871    }
872}