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 every time 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 allocated in the reactive node. This allows us to freely copy
109/// this handle around and use it in closures and event handlers without worrying about ownership of
110/// the 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(
159            self.root
160                .nodes
161                .try_borrow()
162                .expect("cannot read signal while updating"),
163            |nodes| match nodes.get(self.id) {
164                Some(node) => node,
165                None => panic!("{}", self.get_disposed_panic_message()),
166            },
167        )
168    }
169
170    /// Get a mutable reference to the underlying node.
171    #[cfg_attr(debug_assertions, track_caller)]
172    pub(crate) fn get_mut(self) -> RefMut<'static, ReactiveNode> {
173        RefMut::map(
174            self.root
175                .nodes
176                .try_borrow_mut()
177                .expect("cannot update signal while reading"),
178            |nodes| match nodes.get_mut(self.id) {
179                Some(node) => node,
180                None => panic!("{}", self.get_disposed_panic_message()),
181            },
182        )
183    }
184
185    /// Returns `true` if the signal is still alive, i.e. has not yet been disposed.
186    pub fn is_alive(self) -> bool {
187        self.root.nodes.borrow().get(self.id).is_some()
188    }
189
190    /// Disposes the signal, i.e. frees up the memory held on by this signal. Accessing a signal
191    /// after it has been disposed immediately causes a panic.
192    pub fn dispose(self) {
193        NodeHandle(self.id, self.root).dispose();
194    }
195
196    fn get_disposed_panic_message(self) -> String {
197        #[cfg(not(debug_assertions))]
198        return "signal was disposed".to_string();
199
200        #[cfg(debug_assertions)]
201        return format!("signal was disposed. Created at {}", self.created_at);
202    }
203
204    /// Get the value of the signal without tracking it. The type must implement [`Copy`]. If this
205    /// is not the case, use [`ReadSignal::get_clone_untracked`] or [`ReadSignal::with_untracked`]
206    /// instead.
207    ///
208    /// # Example
209    /// ```
210    /// # use sycamore_reactive::*;
211    /// # create_root(|| {
212    /// let state = create_signal(0);
213    /// // Note that we have used `get_untracked` here so the signal is not actually being tracked
214    /// // by the memo.
215    /// let doubled = create_memo(move || state.get_untracked() * 2);
216    /// state.set(1);
217    /// assert_eq!(doubled.get(), 0);
218    /// # });
219    /// ```
220    #[cfg_attr(debug_assertions, track_caller)]
221    pub fn get_untracked(self) -> T
222    where
223        T: Copy,
224    {
225        self.with_untracked(|value| *value)
226    }
227
228    /// Get the value of the signal without tracking it. The type is [`Clone`]-ed automatically.
229    ///
230    /// This is the cloned equivalent of [`ReadSignal::get_untracked`].
231    #[cfg_attr(debug_assertions, track_caller)]
232    pub fn get_clone_untracked(self) -> T
233    where
234        T: Clone,
235    {
236        self.with_untracked(Clone::clone)
237    }
238
239    /// Get the value of the signal. The type must implement [`Copy`]. If this is not the case, use
240    /// [`ReadSignal::get_clone_untracked`] or [`ReadSignal::with_untracked`] instead.
241    ///
242    /// When called inside a reactive scope, the signal will be automatically tracked.
243    ///
244    /// # Example
245    /// ```
246    /// # use sycamore_reactive::*;
247    /// # create_root(|| {
248    /// let state = create_signal(0);
249    /// assert_eq!(state.get(), 0);
250    ///
251    /// state.set(1);
252    /// assert_eq!(state.get(), 1);
253    ///
254    /// // The signal is automatically tracked in the line below.
255    /// let doubled = create_memo(move || state.get());
256    /// # });
257    /// ```
258    #[cfg_attr(debug_assertions, track_caller)]
259    pub fn get(self) -> T
260    where
261        T: Copy,
262    {
263        self.track();
264        self.get_untracked()
265    }
266
267    /// Get the value of the signal. The type is [`Clone`]-ed automatically.
268    ///
269    /// When called inside a reactive scope, the signal will be automatically tracked.
270    ///
271    /// If the value implements [`Copy`], you should use [`ReadSignal::get`] instead.
272    ///
273    /// # Example
274    /// ```
275    /// # use sycamore_reactive::*;
276    /// # create_root(|| {
277    /// let greeting = create_signal("Hello".to_string());
278    /// assert_eq!(greeting.get_clone(), "Hello".to_string());
279    ///
280    /// // The signal is automatically tracked in the line below.
281    /// let hello_world = create_memo(move || format!("{} World!", greeting.get_clone()));
282    /// assert_eq!(hello_world.get_clone(), "Hello World!");
283    ///
284    /// greeting.set("Goodbye".to_string());
285    /// assert_eq!(greeting.get_clone(), "Goodbye".to_string());
286    /// assert_eq!(hello_world.get_clone(), "Goodbye World!");
287    /// # });
288    /// ```
289    #[cfg_attr(debug_assertions, track_caller)]
290    pub fn get_clone(self) -> T
291    where
292        T: Clone,
293    {
294        self.track();
295        self.get_clone_untracked()
296    }
297
298    /// Get a value from the signal without tracking it.
299    #[cfg_attr(debug_assertions, track_caller)]
300    pub fn with_untracked<U>(self, f: impl FnOnce(&T) -> U) -> U {
301        let node = self.get_ref();
302        let value = node
303            .value
304            .as_ref()
305            .expect("cannot read signal while updating");
306        let ret = f(value.downcast_ref().expect("wrong signal type"));
307        ret
308    }
309
310    /// Get a value from the signal.
311    ///
312    /// When called inside a reactive scope, the signal will be automatically tracked.
313    #[cfg_attr(debug_assertions, track_caller)]
314    pub fn with<U>(self, f: impl FnOnce(&T) -> U) -> U {
315        self.track();
316        self.with_untracked(f)
317    }
318
319    /// Creates a new [memo](create_memo) from this signal and a function. The resulting memo will
320    /// be created in the current reactive scope.
321    ///
322    /// # Example
323    /// ```
324    /// # use sycamore_reactive::*;
325    /// # create_root(|| {
326    /// let state = create_signal(0);
327    /// let doubled = state.map(|val| *val * 2);
328    /// assert_eq!(doubled.get(), 0);
329    /// state.set(1);
330    /// assert_eq!(doubled.get(), 2);
331    /// # });
332    /// ```
333    #[cfg_attr(debug_assertions, track_caller)]
334    pub fn map<U>(self, mut f: impl FnMut(&T) -> U + 'static) -> ReadSignal<U> {
335        create_memo(move || self.with(&mut f))
336    }
337
338    /// Track the signal in the current reactive scope. This is done automatically when calling
339    /// [`ReadSignal::get`] and other similar methods.
340    ///
341    /// # Example
342    /// ```
343    /// # use sycamore_reactive::*;
344    /// # create_root(|| {
345    /// let state = create_signal(0);
346    /// create_effect(move || {
347    ///     state.track(); // Track the signal without getting its value.
348    ///     println!("Yipee!");
349    /// });
350    /// state.set(1); // Prints "Yipee!"
351    /// # });
352    /// ```
353    pub fn track(self) {
354        if let Some(tracker) = &mut *self.root.tracker.borrow_mut() {
355            tracker.dependencies.push(self.id);
356        }
357    }
358}
359
360impl<T> Signal<T> {
361    /// Silently set a new value for the signal. This will not trigger any updates in dependent
362    /// signals. As such, this is generally not recommended as it can easily lead to state
363    /// inconsistencies.
364    ///
365    /// # Example
366    /// ```
367    /// # use sycamore_reactive::*;
368    /// # create_root(|| {
369    /// let state = create_signal(0);
370    /// let doubled = create_memo(move || state.get() * 2);
371    /// assert_eq!(doubled.get(), 0);
372    /// state.set_silent(1);
373    /// assert_eq!(doubled.get(), 0); // We now have inconsistent state!
374    /// # });
375    /// ```
376    #[cfg_attr(debug_assertions, track_caller)]
377    pub fn set_silent(self, new: T) {
378        self.replace_silent(new);
379    }
380
381    /// Set a new value for the signal and automatically update any dependents.
382    ///
383    /// # Example
384    /// ```
385    /// # use sycamore_reactive::*;
386    /// # create_root(|| {
387    /// let state = create_signal(0);
388    /// let doubled = create_memo(move || state.get() * 2);
389    /// assert_eq!(doubled.get(), 0);
390    /// state.set(1);
391    /// assert_eq!(doubled.get(), 2);
392    /// # });
393    /// ```
394    #[cfg_attr(debug_assertions, track_caller)]
395    pub fn set(self, new: T) {
396        self.replace(new);
397    }
398
399    /// Silently set a new value for the signal and return the previous value.
400    ///
401    /// This is the silent version of [`Signal::replace`].
402    #[cfg_attr(debug_assertions, track_caller)]
403    pub fn replace_silent(self, new: T) -> T {
404        self.update_silent(|val| std::mem::replace(val, new))
405    }
406
407    /// Set a new value for the signal and return the previous value.
408    ///
409    /// # Example
410    /// ```
411    /// # use sycamore_reactive::*;
412    /// # create_root(|| {
413    /// let state = create_signal(123);
414    /// let prev = state.replace(456);
415    /// assert_eq!(state.get(), 456);
416    /// assert_eq!(prev, 123);
417    /// # });
418    /// ```
419    #[cfg_attr(debug_assertions, track_caller)]
420    pub fn replace(self, new: T) -> T {
421        self.update(|val| std::mem::replace(val, new))
422    }
423
424    /// Silently gets the value of the signal and sets the new value to the default value.
425    ///
426    /// This is the silent version of [`Signal::take`].
427    #[cfg_attr(debug_assertions, track_caller)]
428    pub fn take_silent(self) -> T
429    where
430        T: Default,
431    {
432        self.replace_silent(T::default())
433    }
434
435    /// Gets the value of the signal and sets the new value to the default value.
436    ///
437    /// # Example
438    /// ```
439    /// # use sycamore_reactive::*;
440    /// # create_root(|| {
441    /// let state = create_signal(Some(123));
442    /// let prev = state.take();
443    /// assert_eq!(state.get(), None);
444    /// assert_eq!(prev, Some(123));
445    /// # });
446    /// ```
447    #[cfg_attr(debug_assertions, track_caller)]
448    pub fn take(self) -> T
449    where
450        T: Default,
451    {
452        self.replace(T::default())
453    }
454
455    /// Update the value of the signal silently. This will not trigger any updates in dependent
456    /// signals. As such, this is generally not recommended as it can easily lead to state
457    /// inconsistencies.
458    ///
459    /// This is the silent version of [`Signal::update`].
460    #[cfg_attr(debug_assertions, track_caller)]
461    pub fn update_silent<U>(self, f: impl FnOnce(&mut T) -> U) -> U {
462        let mut value = self
463            .get_mut()
464            .value
465            .take()
466            .expect("cannot update signal while reading");
467        let ret = f(value.downcast_mut().expect("wrong signal type"));
468        self.get_mut().value = Some(value);
469        ret
470    }
471
472    /// Update the value of the signal and automatically update any dependents.
473    ///
474    /// Using this has the advantage of not needing to clone the value when updating it, especially
475    /// with types that do not implement `Copy` where cloning can be expensive, or for types that
476    /// do not implement `Clone` at all.
477    ///
478    /// # Example
479    /// ```
480    /// # use sycamore_reactive::*;
481    /// # create_root(|| {
482    /// let state = create_signal("Hello".to_string());
483    /// state.update(|val| val.push_str(" Sycamore!"));
484    /// assert_eq!(state.get_clone(), "Hello Sycamore!");
485    /// # });
486    /// ```
487    #[cfg_attr(debug_assertions, track_caller)]
488    pub fn update<U>(self, f: impl FnOnce(&mut T) -> U) -> U {
489        let ret = self.update_silent(f);
490        self.0.root.propagate_updates(self.0.id);
491        ret
492    }
493
494    /// Use a function to produce a new value and sets the value silently.
495    ///
496    /// This is the silent version of [`Signal::set_fn`].
497    #[cfg_attr(debug_assertions, track_caller)]
498    pub fn set_fn_silent(self, f: impl FnOnce(&T) -> T) {
499        self.update_silent(move |val| *val = f(val));
500    }
501
502    /// Use a function to produce a new value and sets the value.
503    ///
504    /// # Example
505    /// ```
506    /// # use sycamore_reactive::*;
507    /// # create_root(|| {
508    /// let state = create_signal(123);
509    /// state.set_fn(|val| *val + 1);
510    /// assert_eq!(state.get(), 124);
511    /// # });
512    /// ```
513    #[cfg_attr(debug_assertions, track_caller)]
514    pub fn set_fn(self, f: impl FnOnce(&T) -> T) {
515        self.update(move |val| *val = f(val));
516    }
517
518    /// Split the signal into a reader/writer pair.
519    ///
520    /// # Example
521    /// ```
522    /// # use sycamore_reactive::*;
523    /// # create_root(|| {
524    /// let (read_signal, mut write_signal) = create_signal(0).split();
525    /// assert_eq!(read_signal.get(), 0);
526    /// write_signal(1);
527    /// assert_eq!(read_signal.get(), 1);
528    /// # });
529    /// ```
530    pub fn split(self) -> (ReadSignal<T>, impl Fn(T) -> T) {
531        (*self, move |value| self.replace(value))
532    }
533}
534
535/// We manually implement `Clone` + `Copy` for `Signal` so that we don't get extra bounds on `T`.
536impl<T> Clone for ReadSignal<T> {
537    fn clone(&self) -> Self {
538        *self
539    }
540}
541impl<T> Copy for ReadSignal<T> {}
542
543impl<T> Clone for Signal<T> {
544    fn clone(&self) -> Self {
545        *self
546    }
547}
548impl<T> Copy for Signal<T> {}
549
550// Implement `Default` for `ReadSignal` and `Signal`.
551impl<T: Default> Default for ReadSignal<T> {
552    fn default() -> Self {
553        *create_signal(Default::default())
554    }
555}
556impl<T: Default> Default for Signal<T> {
557    fn default() -> Self {
558        create_signal(Default::default())
559    }
560}
561
562// Forward `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Hash` from inner type.
563impl<T: PartialEq> PartialEq for ReadSignal<T> {
564    fn eq(&self, other: &Self) -> bool {
565        self.with(|value| other.with(|other| value == other))
566    }
567}
568impl<T: Eq> Eq for ReadSignal<T> {}
569impl<T: PartialOrd> PartialOrd for ReadSignal<T> {
570    #[cfg_attr(debug_assertions, track_caller)]
571    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
572        self.with(|value| other.with(|other| value.partial_cmp(other)))
573    }
574}
575impl<T: Ord> Ord for ReadSignal<T> {
576    #[cfg_attr(debug_assertions, track_caller)]
577    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
578        self.with(|value| other.with(|other| value.cmp(other)))
579    }
580}
581impl<T: Hash> Hash for ReadSignal<T> {
582    #[cfg_attr(debug_assertions, track_caller)]
583    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
584        self.with(|value| value.hash(state))
585    }
586}
587
588impl<T: PartialEq> PartialEq for Signal<T> {
589    #[cfg_attr(debug_assertions, track_caller)]
590    fn eq(&self, other: &Self) -> bool {
591        self.with(|value| other.with(|other| value == other))
592    }
593}
594impl<T: Eq> Eq for Signal<T> {}
595impl<T: PartialOrd> PartialOrd for Signal<T> {
596    #[cfg_attr(debug_assertions, track_caller)]
597    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
598        self.with(|value| other.with(|other| value.partial_cmp(other)))
599    }
600}
601impl<T: Ord> Ord for Signal<T> {
602    #[cfg_attr(debug_assertions, track_caller)]
603    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
604        self.with(|value| other.with(|other| value.cmp(other)))
605    }
606}
607impl<T: Hash> Hash for Signal<T> {
608    #[cfg_attr(debug_assertions, track_caller)]
609    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
610        self.with(|value| value.hash(state))
611    }
612}
613
614impl<T> Deref for Signal<T> {
615    type Target = ReadSignal<T>;
616
617    fn deref(&self) -> &Self::Target {
618        &self.0
619    }
620}
621
622// Formatting implementations for `ReadSignal` and `Signal`.
623impl<T: fmt::Debug> fmt::Debug for ReadSignal<T> {
624    #[cfg_attr(debug_assertions, track_caller)]
625    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
626        self.with(|value| value.fmt(f))
627    }
628}
629impl<T: fmt::Debug> fmt::Debug for Signal<T> {
630    #[cfg_attr(debug_assertions, track_caller)]
631    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
632        self.with(|value| value.fmt(f))
633    }
634}
635
636impl<T: fmt::Display> fmt::Display for ReadSignal<T> {
637    #[cfg_attr(debug_assertions, track_caller)]
638    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
639        self.with(|value| value.fmt(f))
640    }
641}
642impl<T: fmt::Display> fmt::Display for Signal<T> {
643    #[cfg_attr(debug_assertions, track_caller)]
644    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
645        self.with(|value| value.fmt(f))
646    }
647}
648
649// Serde implementations for `ReadSignal` and `Signal`.
650#[cfg(feature = "serde")]
651impl<T: serde::Serialize> serde::Serialize for ReadSignal<T> {
652    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
653        self.with(|value| value.serialize(serializer))
654    }
655}
656#[cfg(feature = "serde")]
657impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for ReadSignal<T> {
658    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
659        Ok(*create_signal(T::deserialize(deserializer)?))
660    }
661}
662#[cfg(feature = "serde")]
663impl<T: serde::Serialize> serde::Serialize for Signal<T> {
664    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
665        self.with(|value| value.serialize(serializer))
666    }
667}
668#[cfg(feature = "serde")]
669impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Signal<T> {
670    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
671        Ok(create_signal(T::deserialize(deserializer)?))
672    }
673}
674
675#[cfg(feature = "nightly")]
676impl<T: Copy> FnOnce<()> for ReadSignal<T> {
677    type Output = T;
678
679    extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
680        self.get()
681    }
682}
683
684impl<T: AddAssign<Rhs>, Rhs> AddAssign<Rhs> for Signal<T> {
685    fn add_assign(&mut self, rhs: Rhs) {
686        self.update(|this| *this += rhs);
687    }
688}
689impl<T: SubAssign<Rhs>, Rhs> SubAssign<Rhs> for Signal<T> {
690    fn sub_assign(&mut self, rhs: Rhs) {
691        self.update(|this| *this -= rhs);
692    }
693}
694impl<T: MulAssign<Rhs>, Rhs> MulAssign<Rhs> for Signal<T> {
695    fn mul_assign(&mut self, rhs: Rhs) {
696        self.update(|this| *this *= rhs);
697    }
698}
699impl<T: DivAssign<Rhs>, Rhs> DivAssign<Rhs> for Signal<T> {
700    fn div_assign(&mut self, rhs: Rhs) {
701        self.update(|this| *this /= rhs);
702    }
703}
704impl<T: RemAssign<Rhs>, Rhs> RemAssign<Rhs> for Signal<T> {
705    fn rem_assign(&mut self, rhs: Rhs) {
706        self.update(|this| *this %= rhs);
707    }
708}
709
710// We need to implement this again for `Signal` despite `Signal` deref-ing to `ReadSignal` since
711// we also have another implementation of `FnOnce` for `Signal`.
712#[cfg(feature = "nightly")]
713impl<T: Copy> FnOnce<()> for Signal<T> {
714    type Output = T;
715
716    extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
717        self.get()
718    }
719}
720
721#[cfg(feature = "nightly")]
722impl<T: Copy> FnOnce<(T,)> for Signal<T> {
723    type Output = T;
724
725    extern "rust-call" fn call_once(self, (val,): (T,)) -> Self::Output {
726        self.replace(val)
727    }
728}
729
730#[cfg(test)]
731mod tests {
732    use crate::*;
733
734    #[test]
735    fn signal() {
736        let _ = create_root(|| {
737            let state = create_signal(0);
738            assert_eq!(state.get(), 0);
739
740            state.set(1);
741            assert_eq!(state.get(), 1);
742
743            state.set_fn(|n| *n + 1);
744            assert_eq!(state.get(), 2);
745        });
746    }
747
748    #[test]
749    fn signal_composition() {
750        let _ = create_root(|| {
751            let state = create_signal(0);
752            let double = || state.get() * 2;
753
754            assert_eq!(double(), 0);
755            state.set(1);
756            assert_eq!(double(), 2);
757        });
758    }
759
760    #[test]
761    fn set_silent_signal() {
762        let _ = create_root(|| {
763            let state = create_signal(0);
764            let double = state.map(|&x| x * 2);
765
766            assert_eq!(double.get(), 0);
767            state.set_silent(1);
768            assert_eq!(double.get(), 0); // double value is unchanged.
769
770            state.set_fn_silent(|n| n + 1);
771            assert_eq!(double.get(), 0); // double value is unchanged.
772        });
773    }
774
775    #[test]
776    fn read_signal() {
777        let _ = create_root(|| {
778            let state = create_signal(0);
779            let readonly: ReadSignal<i32> = *state;
780
781            assert_eq!(readonly.get(), 0);
782            state.set(1);
783            assert_eq!(readonly.get(), 1);
784        });
785    }
786
787    #[test]
788    fn map_signal() {
789        let _ = create_root(|| {
790            let state = create_signal(0);
791            let double = state.map(|&x| x * 2);
792
793            assert_eq!(double.get(), 0);
794            state.set(1);
795            assert_eq!(double.get(), 2);
796        });
797    }
798
799    #[test]
800    fn take_signal() {
801        let _ = create_root(|| {
802            let state = create_signal(123);
803
804            let x = state.take();
805            assert_eq!(x, 123);
806            assert_eq!(state.get(), 0);
807        });
808    }
809
810    #[test]
811    fn take_silent_signal() {
812        let _ = create_root(|| {
813            let state = create_signal(123);
814            let double = state.map(|&x| x * 2);
815
816            // Do not trigger subscribers.
817            state.take_silent();
818            assert_eq!(state.get(), 0);
819            assert_eq!(double.get(), 246);
820        });
821    }
822
823    #[test]
824    fn signal_split() {
825        let _ = create_root(|| {
826            let (state, set_state) = create_signal(0).split();
827            assert_eq!(state.get(), 0);
828
829            set_state(1);
830            assert_eq!(state.get(), 1);
831        });
832    }
833
834    #[test]
835    fn signal_display() {
836        let _ = create_root(|| {
837            let signal = create_signal(0);
838            assert_eq!(format!("{signal}"), "0");
839            let read_signal: ReadSignal<_> = *signal;
840            assert_eq!(format!("{read_signal}"), "0");
841            let memo = create_memo(|| 0);
842            assert_eq!(format!("{memo}"), "0");
843        });
844    }
845
846    #[test]
847    fn signal_debug() {
848        let _ = create_root(|| {
849            let signal = create_signal(0);
850            assert_eq!(format!("{signal:?}"), "0");
851            let read_signal: ReadSignal<_> = *signal;
852            assert_eq!(format!("{read_signal:?}"), "0");
853            let memo = create_memo(|| 0);
854            assert_eq!(format!("{memo:?}"), "0");
855        });
856    }
857
858    #[test]
859    fn signal_add_assign_update() {
860        let _ = create_root(|| {
861            let mut signal = create_signal(0);
862            let counter = create_signal(0);
863            create_effect(move || {
864                signal.track();
865                counter.set(counter.get_untracked() + 1);
866            });
867            signal += 1;
868            signal -= 1;
869            signal *= 1;
870            signal /= 1;
871            assert_eq!(counter.get(), 5);
872        });
873    }
874
875    #[test]
876    fn signal_update() {
877        let _ = create_root(|| {
878            let signal = create_signal("Hello ".to_string());
879            let counter = create_signal(0);
880            create_effect(move || {
881                signal.track();
882                counter.set(counter.get_untracked() + 1);
883            });
884            signal.update(|value| value.push_str("World!"));
885            assert_eq!(signal.get_clone(), "Hello World!");
886            assert_eq!(counter.get(), 2);
887        });
888    }
889}