reactive_graph/
wrappers.rs

1//! Types to abstract over different kinds of readable or writable reactive values.
2
3/// Types that abstract over signals with values that can be read.
4pub mod read {
5    use crate::{
6        computed::{ArcMemo, Memo},
7        graph::untrack,
8        owner::{
9            ArcStoredValue, ArenaItem, FromLocal, LocalStorage, Storage,
10            SyncStorage,
11        },
12        signal::{
13            guards::{Mapped, Plain, ReadGuard},
14            ArcMappedSignal, ArcReadSignal, ArcRwSignal, MappedSignal,
15            ReadSignal, RwSignal,
16        },
17        traits::{
18            DefinedAt, Dispose, Get, Read, ReadUntracked, ReadValue, Track,
19        },
20        unwrap_signal,
21    };
22    use send_wrapper::SendWrapper;
23    use std::{
24        borrow::Borrow,
25        fmt::Display,
26        ops::Deref,
27        panic::Location,
28        sync::{Arc, RwLock},
29    };
30
31    /// Possibilities for the inner type of a [`Signal`].
32    pub enum SignalTypes<T, S = SyncStorage>
33    where
34        S: Storage<T>,
35    {
36        /// A readable signal.
37        ReadSignal(ArcReadSignal<T>),
38        /// A memo.
39        Memo(ArcMemo<T, S>),
40        /// A derived signal.
41        DerivedSignal(Arc<dyn Fn() -> T + Send + Sync>),
42        /// A static, stored value.
43        Stored(ArcStoredValue<T>),
44    }
45
46    impl<T, S> Clone for SignalTypes<T, S>
47    where
48        S: Storage<T>,
49    {
50        fn clone(&self) -> Self {
51            match self {
52                Self::ReadSignal(arg0) => Self::ReadSignal(arg0.clone()),
53                Self::Memo(arg0) => Self::Memo(arg0.clone()),
54                Self::DerivedSignal(arg0) => Self::DerivedSignal(arg0.clone()),
55                Self::Stored(arg0) => Self::Stored(arg0.clone()),
56            }
57        }
58    }
59
60    impl<T, S> core::fmt::Debug for SignalTypes<T, S>
61    where
62        S: Storage<T>,
63    {
64        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
65            match self {
66                Self::ReadSignal(arg0) => {
67                    f.debug_tuple("ReadSignal").field(arg0).finish()
68                }
69                Self::Memo(arg0) => f.debug_tuple("Memo").field(arg0).finish(),
70                Self::DerivedSignal(_) => {
71                    f.debug_tuple("DerivedSignal").finish()
72                }
73                Self::Stored(arg0) => {
74                    f.debug_tuple("Static").field(arg0).finish()
75                }
76            }
77        }
78    }
79
80    impl<T, S> PartialEq for SignalTypes<T, S>
81    where
82        S: Storage<T>,
83    {
84        fn eq(&self, other: &Self) -> bool {
85            match (self, other) {
86                (Self::ReadSignal(l0), Self::ReadSignal(r0)) => l0 == r0,
87                (Self::Memo(l0), Self::Memo(r0)) => l0 == r0,
88                (Self::DerivedSignal(l0), Self::DerivedSignal(r0)) => {
89                    std::ptr::eq(l0, r0)
90                }
91                _ => false,
92            }
93        }
94    }
95
96    /// A wrapper for any kind of reference-counted reactive signal:
97    /// an [`ArcReadSignal`], [`ArcMemo`], [`ArcRwSignal`], or derived signal closure,
98    /// or a plain value of the same type
99    ///
100    /// This allows you to create APIs that take `T` or any reactive value that returns `T`
101    /// as an argument, rather than adding a generic `F: Fn() -> T`.
102    ///
103    /// Values can be accessed with the same function call, `read()`, `with()`, and `get()`
104    /// APIs as other signals.
105    ///
106    /// ## Important Notes about Derived Signals
107    ///
108    /// `Signal::derive()` is simply a way to box and type-erase a “derived signal,” which
109    /// is a plain closure that accesses one or more signals. It does *not* cache the value
110    /// of that computation. Accessing the value of a `Signal<_>` that is created using `Signal::derive()`
111    /// will run the closure again every time you call `.read()`, `.with()`, or `.get()`.
112    ///
113    /// If you want the closure to run the minimal number of times necessary to update its state,
114    /// and then to cache its value, you should use a [`Memo`] (and convert it into a `Signal<_>`)
115    /// rather than using `Signal::derive()`.
116    ///
117    /// Note that for many computations, it is nevertheless less expensive to use a derived signal
118    /// than to create a separate memo and to cache the value: creating a new reactive node and
119    /// taking the lock on that cached value whenever you access the signal is *more* expensive than
120    /// simply re-running the calculation in many cases.
121    pub struct ArcSignal<T: 'static, S = SyncStorage>
122    where
123        S: Storage<T>,
124    {
125        #[cfg(any(debug_assertions, leptos_debuginfo))]
126        defined_at: &'static Location<'static>,
127        inner: SignalTypes<T, S>,
128    }
129
130    impl<T, S> Clone for ArcSignal<T, S>
131    where
132        S: Storage<T>,
133    {
134        fn clone(&self) -> Self {
135            Self {
136                #[cfg(any(debug_assertions, leptos_debuginfo))]
137                defined_at: self.defined_at,
138                inner: self.inner.clone(),
139            }
140        }
141    }
142
143    impl<T, S> core::fmt::Debug for ArcSignal<T, S>
144    where
145        S: Storage<T>,
146    {
147        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
148            let mut s = f.debug_struct("ArcSignal");
149            s.field("inner", &self.inner);
150            #[cfg(any(debug_assertions, leptos_debuginfo))]
151            s.field("defined_at", &self.defined_at);
152            s.finish()
153        }
154    }
155
156    impl<T, S> Eq for ArcSignal<T, S> where S: Storage<T> {}
157
158    impl<T, S> PartialEq for ArcSignal<T, S>
159    where
160        S: Storage<T>,
161    {
162        fn eq(&self, other: &Self) -> bool {
163            self.inner == other.inner
164        }
165    }
166
167    impl<T> ArcSignal<T, SyncStorage>
168    where
169        SyncStorage: Storage<T>,
170    {
171        /// Wraps a derived signal, i.e., any computation that accesses one or more
172        /// reactive signals.
173        /// ```rust
174        /// # use reactive_graph::signal::*; let owner = reactive_graph::owner::Owner::new(); owner.set();
175        /// # use reactive_graph::wrappers::read::ArcSignal;
176        /// # use reactive_graph::prelude::*;
177        /// let (count, set_count) = arc_signal(2);
178        /// let double_count = ArcSignal::derive({
179        ///     let count = count.clone();
180        ///     move || count.get() * 2
181        /// });
182        ///
183        /// // this function takes any kind of wrapped signal
184        /// fn above_3(arg: &ArcSignal<i32>) -> bool {
185        ///     arg.get() > 3
186        /// }
187        ///
188        /// assert_eq!(above_3(&count.into()), false);
189        /// assert_eq!(above_3(&double_count), true);
190        /// ```
191        #[track_caller]
192        pub fn derive(
193            derived_signal: impl Fn() -> T + Send + Sync + 'static,
194        ) -> Self {
195            #[cfg(feature = "tracing")]
196            let span = ::tracing::Span::current();
197
198            let derived_signal = move || {
199                #[cfg(feature = "tracing")]
200                let _guard = span.enter();
201                derived_signal()
202            };
203
204            Self {
205                inner: SignalTypes::DerivedSignal(Arc::new(derived_signal)),
206                #[cfg(any(debug_assertions, leptos_debuginfo))]
207                defined_at: std::panic::Location::caller(),
208            }
209        }
210
211        /// Moves a static, nonreactive value into a signal, backed by [`ArcStoredValue`].
212        #[track_caller]
213        pub fn stored(value: T) -> Self {
214            Self {
215                inner: SignalTypes::Stored(ArcStoredValue::new(value)),
216                #[cfg(any(debug_assertions, leptos_debuginfo))]
217                defined_at: std::panic::Location::caller(),
218            }
219        }
220    }
221
222    impl<T> ArcSignal<T, LocalStorage>
223    where
224        T: 'static,
225    {
226        /// Wraps a derived signal. Works like [`Signal::derive`] but uses [`LocalStorage`].
227        #[track_caller]
228        pub fn derive_local(derived_signal: impl Fn() -> T + 'static) -> Self {
229            Signal::derive_local(derived_signal).into()
230        }
231
232        /// Moves a static, nonreactive value into a signal, backed by [`ArcStoredValue`].
233        /// Works like [`Signal::stored`] but uses [`LocalStorage`].
234        #[track_caller]
235        pub fn stored_local(value: T) -> Self {
236            Signal::stored_local(value).into()
237        }
238    }
239
240    impl<T> Default for ArcSignal<T, SyncStorage>
241    where
242        T: Default + Send + Sync + 'static,
243    {
244        fn default() -> Self {
245            Self::stored(Default::default())
246        }
247    }
248
249    impl<T: Send + Sync> From<ArcReadSignal<T>> for ArcSignal<T, SyncStorage> {
250        #[track_caller]
251        fn from(value: ArcReadSignal<T>) -> Self {
252            Self {
253                inner: SignalTypes::ReadSignal(value),
254                #[cfg(any(debug_assertions, leptos_debuginfo))]
255                defined_at: std::panic::Location::caller(),
256            }
257        }
258    }
259
260    impl<T, S> From<ReadSignal<T, S>> for ArcSignal<T, S>
261    where
262        S: Storage<ArcReadSignal<T>> + Storage<T>,
263    {
264        #[track_caller]
265        fn from(value: ReadSignal<T, S>) -> Self {
266            Self {
267                inner: SignalTypes::ReadSignal(value.into()),
268                #[cfg(any(debug_assertions, leptos_debuginfo))]
269                defined_at: std::panic::Location::caller(),
270            }
271        }
272    }
273
274    impl<T: Send + Sync> From<ArcRwSignal<T>> for ArcSignal<T, SyncStorage> {
275        #[track_caller]
276        fn from(value: ArcRwSignal<T>) -> Self {
277            Self {
278                inner: SignalTypes::ReadSignal(value.read_only()),
279                #[cfg(any(debug_assertions, leptos_debuginfo))]
280                defined_at: std::panic::Location::caller(),
281            }
282        }
283    }
284
285    impl<T, S> From<RwSignal<T, S>> for ArcSignal<T, S>
286    where
287        S: Storage<ArcRwSignal<T>> + Storage<ArcReadSignal<T>> + Storage<T>,
288    {
289        #[track_caller]
290        fn from(value: RwSignal<T, S>) -> Self {
291            Self {
292                inner: SignalTypes::ReadSignal(value.read_only().into()),
293                #[cfg(any(debug_assertions, leptos_debuginfo))]
294                defined_at: std::panic::Location::caller(),
295            }
296        }
297    }
298
299    impl<T, S> From<ArcMemo<T, S>> for ArcSignal<T, S>
300    where
301        S: Storage<T>,
302    {
303        #[track_caller]
304        fn from(value: ArcMemo<T, S>) -> Self {
305            Self {
306                inner: SignalTypes::Memo(value),
307                #[cfg(any(debug_assertions, leptos_debuginfo))]
308                defined_at: std::panic::Location::caller(),
309            }
310        }
311    }
312
313    impl<T, S> From<Memo<T, S>> for ArcSignal<T, S>
314    where
315        S: Storage<ArcMemo<T, S>> + Storage<T>,
316    {
317        #[track_caller]
318        fn from(value: Memo<T, S>) -> Self {
319            Self {
320                inner: SignalTypes::Memo(value.into()),
321                #[cfg(any(debug_assertions, leptos_debuginfo))]
322                defined_at: std::panic::Location::caller(),
323            }
324        }
325    }
326
327    impl<T, S> DefinedAt for ArcSignal<T, S>
328    where
329        S: Storage<T>,
330    {
331        fn defined_at(&self) -> Option<&'static Location<'static>> {
332            #[cfg(any(debug_assertions, leptos_debuginfo))]
333            {
334                Some(self.defined_at)
335            }
336            #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
337            {
338                None
339            }
340        }
341    }
342
343    impl<T, S> Track for ArcSignal<T, S>
344    where
345        S: Storage<T>,
346    {
347        fn track(&self) {
348            match &self.inner {
349                SignalTypes::ReadSignal(i) => {
350                    i.track();
351                }
352                SignalTypes::Memo(i) => {
353                    i.track();
354                }
355                SignalTypes::DerivedSignal(i) => {
356                    i();
357                }
358                // Doesn't change.
359                SignalTypes::Stored(_) => {}
360            }
361        }
362    }
363
364    impl<T, S> ReadUntracked for ArcSignal<T, S>
365    where
366        S: Storage<T>,
367    {
368        type Value = ReadGuard<T, SignalReadGuard<T, S>>;
369
370        fn try_read_untracked(&self) -> Option<Self::Value> {
371            match &self.inner {
372                SignalTypes::ReadSignal(i) => {
373                    i.try_read_untracked().map(SignalReadGuard::Read)
374                }
375                SignalTypes::Memo(i) => {
376                    i.try_read_untracked().map(SignalReadGuard::Memo)
377                }
378                SignalTypes::DerivedSignal(i) => {
379                    Some(SignalReadGuard::Owned(untrack(|| i())))
380                }
381                SignalTypes::Stored(i) => {
382                    i.try_read_value().map(SignalReadGuard::Read)
383                }
384            }
385            .map(ReadGuard::new)
386        }
387
388        /// Overriding the default auto implemented [`Read::try_read`] to combine read and track,
389        /// to avoid 2 clones and just have 1 in the [`SignalTypes::DerivedSignal`].
390        fn custom_try_read(&self) -> Option<Option<Self::Value>> {
391            Some(
392                match &self.inner {
393                    SignalTypes::ReadSignal(i) => {
394                        i.try_read().map(SignalReadGuard::Read)
395                    }
396                    SignalTypes::Memo(i) => {
397                        i.try_read().map(SignalReadGuard::Memo)
398                    }
399                    SignalTypes::DerivedSignal(i) => {
400                        Some(SignalReadGuard::Owned(i()))
401                    }
402                    SignalTypes::Stored(i) => {
403                        i.try_read_value().map(SignalReadGuard::Read)
404                    }
405                }
406                .map(ReadGuard::new),
407            )
408        }
409    }
410
411    /// A wrapper for any kind of arena-allocated reactive signal:
412    /// a [`ReadSignal`], [`Memo`], [`RwSignal`], or derived signal closure,
413    /// or a plain value of the same type
414    ///
415    /// This allows you to create APIs that take `T` or any reactive value that returns `T`
416    /// as an argument, rather than adding a generic `F: Fn() -> T`.
417    ///
418    /// Values can be accessed with the same function call, `read()`, `with()`, and `get()`
419    /// APIs as other signals.
420    ///
421    /// ## Important Notes about Derived Signals
422    ///
423    /// `Signal::derive()` is simply a way to box and type-erase a “derived signal,” which
424    /// is a plain closure that accesses one or more signals. It does *not* cache the value
425    /// of that computation. Accessing the value of a `Signal<_>` that is created using `Signal::derive()`
426    /// will run the closure again every time you call `.read()`, `.with()`, or `.get()`.
427    ///
428    /// If you want the closure to run the minimal number of times necessary to update its state,
429    /// and then to cache its value, you should use a [`Memo`] (and convert it into a `Signal<_>`)
430    /// rather than using `Signal::derive()`.
431    ///
432    /// Note that for many computations, it is nevertheless less expensive to use a derived signal
433    /// than to create a separate memo and to cache the value: creating a new reactive node and
434    /// taking the lock on that cached value whenever you access the signal is *more* expensive than
435    /// simply re-running the calculation in many cases.
436    pub struct Signal<T, S = SyncStorage>
437    where
438        S: Storage<T>,
439    {
440        #[cfg(any(debug_assertions, leptos_debuginfo))]
441        defined_at: &'static Location<'static>,
442        inner: ArenaItem<SignalTypes<T, S>, S>,
443    }
444
445    impl<T, S> Dispose for Signal<T, S>
446    where
447        S: Storage<T>,
448    {
449        fn dispose(self) {
450            self.inner.dispose()
451        }
452    }
453
454    impl<T, S> Clone for Signal<T, S>
455    where
456        S: Storage<T>,
457    {
458        fn clone(&self) -> Self {
459            *self
460        }
461    }
462
463    impl<T, S> Copy for Signal<T, S> where S: Storage<T> {}
464
465    impl<T, S> core::fmt::Debug for Signal<T, S>
466    where
467        S: std::fmt::Debug + Storage<T>,
468    {
469        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
470            let mut s = f.debug_struct("Signal");
471            s.field("inner", &self.inner);
472            #[cfg(any(debug_assertions, leptos_debuginfo))]
473            s.field("defined_at", &self.defined_at);
474            s.finish()
475        }
476    }
477
478    impl<T, S> Eq for Signal<T, S> where S: Storage<T> {}
479
480    impl<T, S> PartialEq for Signal<T, S>
481    where
482        S: Storage<T>,
483    {
484        fn eq(&self, other: &Self) -> bool {
485            self.inner == other.inner
486        }
487    }
488
489    impl<T, S> DefinedAt for Signal<T, S>
490    where
491        S: Storage<T>,
492    {
493        fn defined_at(&self) -> Option<&'static Location<'static>> {
494            #[cfg(any(debug_assertions, leptos_debuginfo))]
495            {
496                Some(self.defined_at)
497            }
498            #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
499            {
500                None
501            }
502        }
503    }
504
505    impl<T, S> Track for Signal<T, S>
506    where
507        T: 'static,
508        S: Storage<T> + Storage<SignalTypes<T, S>>,
509    {
510        fn track(&self) {
511            let inner = self
512                .inner
513                // clone the inner Arc type and release the lock
514                // prevents deadlocking if the derived value includes taking a lock on the arena
515                .try_with_value(Clone::clone)
516                .unwrap_or_else(unwrap_signal!(self));
517            match inner {
518                SignalTypes::ReadSignal(i) => {
519                    i.track();
520                }
521                SignalTypes::Memo(i) => {
522                    i.track();
523                }
524                SignalTypes::DerivedSignal(i) => {
525                    i();
526                }
527                // Doesn't change.
528                SignalTypes::Stored(_) => {}
529            }
530        }
531    }
532
533    impl<T, S> ReadUntracked for Signal<T, S>
534    where
535        T: 'static,
536        S: Storage<SignalTypes<T, S>> + Storage<T>,
537    {
538        type Value = ReadGuard<T, SignalReadGuard<T, S>>;
539
540        fn try_read_untracked(&self) -> Option<Self::Value> {
541            self.inner
542                // clone the inner Arc type and release the lock
543                // prevents deadlocking if the derived value includes taking a lock on the arena
544                .try_with_value(Clone::clone)
545                .and_then(|inner| {
546                    match &inner {
547                        SignalTypes::ReadSignal(i) => {
548                            i.try_read_untracked().map(SignalReadGuard::Read)
549                        }
550                        SignalTypes::Memo(i) => {
551                            i.try_read_untracked().map(SignalReadGuard::Memo)
552                        }
553                        SignalTypes::DerivedSignal(i) => {
554                            Some(SignalReadGuard::Owned(untrack(|| i())))
555                        }
556                        SignalTypes::Stored(i) => {
557                            i.try_read_value().map(SignalReadGuard::Read)
558                        }
559                    }
560                    .map(ReadGuard::new)
561                })
562        }
563
564        /// Overriding the default auto implemented [`Read::try_read`] to combine read and track,
565        /// to avoid 2 clones and just have 1 in the [`SignalTypes::DerivedSignal`].
566        fn custom_try_read(&self) -> Option<Option<Self::Value>> {
567            Some(
568                self.inner
569                    // clone the inner Arc type and release the lock
570                    // prevents deadlocking if the derived value includes taking a lock on the arena
571                    .try_with_value(Clone::clone)
572                    .and_then(|inner| {
573                        match &inner {
574                            SignalTypes::ReadSignal(i) => {
575                                i.try_read().map(SignalReadGuard::Read)
576                            }
577                            SignalTypes::Memo(i) => {
578                                i.try_read().map(SignalReadGuard::Memo)
579                            }
580                            SignalTypes::DerivedSignal(i) => {
581                                Some(SignalReadGuard::Owned(i()))
582                            }
583                            SignalTypes::Stored(i) => {
584                                i.try_read_value().map(SignalReadGuard::Read)
585                            }
586                        }
587                        .map(ReadGuard::new)
588                    }),
589            )
590        }
591    }
592
593    impl<T> Signal<T>
594    where
595        T: Send + Sync + 'static,
596    {
597        /// Wraps a derived signal, i.e., any computation that accesses one or more
598        /// reactive signals.
599        /// ```rust
600        /// # use reactive_graph::signal::*; let owner = reactive_graph::owner::Owner::new(); owner.set();
601        /// # use reactive_graph::wrappers::read::Signal;
602        /// # use reactive_graph::prelude::*;
603        /// let (count, set_count) = signal(2);
604        /// let double_count = Signal::derive(move || count.get() * 2);
605        ///
606        /// // this function takes any kind of wrapped signal
607        /// fn above_3(arg: &Signal<i32>) -> bool {
608        ///     arg.get() > 3
609        /// }
610        ///
611        /// assert_eq!(above_3(&count.into()), false);
612        /// assert_eq!(above_3(&double_count), true);
613        /// ```
614        #[track_caller]
615        pub fn derive(
616            derived_signal: impl Fn() -> T + Send + Sync + 'static,
617        ) -> Self {
618            #[cfg(feature = "tracing")]
619            let span = ::tracing::Span::current();
620
621            let derived_signal = move || {
622                #[cfg(feature = "tracing")]
623                let _guard = span.enter();
624                derived_signal()
625            };
626
627            Self {
628                inner: ArenaItem::new_with_storage(SignalTypes::DerivedSignal(
629                    Arc::new(derived_signal),
630                )),
631                #[cfg(any(debug_assertions, leptos_debuginfo))]
632                defined_at: std::panic::Location::caller(),
633            }
634        }
635
636        /// Moves a static, nonreactive value into a signal, backed by [`ArcStoredValue`].
637        #[track_caller]
638        pub fn stored(value: T) -> Self {
639            Self {
640                inner: ArenaItem::new_with_storage(SignalTypes::Stored(
641                    ArcStoredValue::new(value),
642                )),
643                #[cfg(any(debug_assertions, leptos_debuginfo))]
644                defined_at: std::panic::Location::caller(),
645            }
646        }
647    }
648
649    impl<T> Signal<T, LocalStorage>
650    where
651        T: 'static,
652    {
653        /// Wraps a derived signal. Works like [`Signal::derive`] but uses [`LocalStorage`].
654        #[track_caller]
655        pub fn derive_local(derived_signal: impl Fn() -> T + 'static) -> Self {
656            let derived_signal = SendWrapper::new(derived_signal);
657            #[cfg(feature = "tracing")]
658            let span = ::tracing::Span::current();
659
660            let derived_signal = move || {
661                #[cfg(feature = "tracing")]
662                let _guard = span.enter();
663                derived_signal()
664            };
665
666            Self {
667                inner: ArenaItem::new_local(SignalTypes::DerivedSignal(
668                    Arc::new(derived_signal),
669                )),
670                #[cfg(any(debug_assertions, leptos_debuginfo))]
671                defined_at: std::panic::Location::caller(),
672            }
673        }
674
675        /// Moves a static, nonreactive value into a signal, backed by [`ArcStoredValue`].
676        /// Works like [`Signal::stored`] but uses [`LocalStorage`].
677        #[track_caller]
678        pub fn stored_local(value: T) -> Self {
679            Self {
680                inner: ArenaItem::new_local(SignalTypes::Stored(
681                    ArcStoredValue::new(value),
682                )),
683                #[cfg(any(debug_assertions, leptos_debuginfo))]
684                defined_at: std::panic::Location::caller(),
685            }
686        }
687    }
688
689    impl<T> Default for Signal<T>
690    where
691        T: Send + Sync + Default + 'static,
692    {
693        fn default() -> Self {
694            Self::stored(Default::default())
695        }
696    }
697
698    impl<T> Default for Signal<T, LocalStorage>
699    where
700        T: Default + 'static,
701    {
702        fn default() -> Self {
703            Self::stored_local(Default::default())
704        }
705    }
706
707    impl<T: Send + Sync + 'static> From<T> for ArcSignal<T, SyncStorage> {
708        #[track_caller]
709        fn from(value: T) -> Self {
710            ArcSignal::stored(value)
711        }
712    }
713
714    impl<T> From<T> for Signal<T>
715    where
716        T: Send + Sync + 'static,
717    {
718        #[track_caller]
719        fn from(value: T) -> Self {
720            Self::stored(value)
721        }
722    }
723
724    impl<T> From<T> for Signal<T, LocalStorage>
725    where
726        T: 'static,
727    {
728        #[track_caller]
729        fn from(value: T) -> Self {
730            Self::stored_local(value)
731        }
732    }
733
734    impl<T> From<ArcSignal<T, SyncStorage>> for Signal<T>
735    where
736        T: Send + Sync + 'static,
737    {
738        #[track_caller]
739        fn from(value: ArcSignal<T, SyncStorage>) -> Self {
740            Signal {
741                #[cfg(any(debug_assertions, leptos_debuginfo))]
742                defined_at: Location::caller(),
743                inner: ArenaItem::new(value.inner),
744            }
745        }
746    }
747
748    impl<T> FromLocal<ArcSignal<T, LocalStorage>> for Signal<T, LocalStorage>
749    where
750        T: 'static,
751    {
752        #[track_caller]
753        fn from_local(value: ArcSignal<T, LocalStorage>) -> Self {
754            Signal {
755                #[cfg(any(debug_assertions, leptos_debuginfo))]
756                defined_at: Location::caller(),
757                inner: ArenaItem::new_local(value.inner),
758            }
759        }
760    }
761
762    impl<T, S> From<Signal<T, S>> for ArcSignal<T, S>
763    where
764        S: Storage<SignalTypes<T, S>> + Storage<T>,
765    {
766        #[track_caller]
767        fn from(value: Signal<T, S>) -> Self {
768            ArcSignal {
769                #[cfg(any(debug_assertions, leptos_debuginfo))]
770                defined_at: Location::caller(),
771                inner: value
772                    .inner
773                    .try_get_value()
774                    .unwrap_or_else(unwrap_signal!(value)),
775            }
776        }
777    }
778
779    impl<T> From<ReadSignal<T>> for Signal<T>
780    where
781        T: Send + Sync + 'static,
782    {
783        #[track_caller]
784        fn from(value: ReadSignal<T>) -> Self {
785            Self {
786                inner: ArenaItem::new(SignalTypes::ReadSignal(value.into())),
787                #[cfg(any(debug_assertions, leptos_debuginfo))]
788                defined_at: std::panic::Location::caller(),
789            }
790        }
791    }
792
793    impl<T> From<ReadSignal<T, LocalStorage>> for Signal<T, LocalStorage>
794    where
795        T: 'static,
796    {
797        #[track_caller]
798        fn from(value: ReadSignal<T, LocalStorage>) -> Self {
799            Self {
800                inner: ArenaItem::new_local(SignalTypes::ReadSignal(
801                    value.into(),
802                )),
803                #[cfg(any(debug_assertions, leptos_debuginfo))]
804                defined_at: std::panic::Location::caller(),
805            }
806        }
807    }
808
809    impl<T> From<ArcReadSignal<T>> for Signal<T>
810    where
811        T: Send + Sync + 'static,
812    {
813        #[track_caller]
814        fn from(value: ArcReadSignal<T>) -> Self {
815            Self {
816                inner: ArenaItem::new(SignalTypes::ReadSignal(value)),
817                #[cfg(any(debug_assertions, leptos_debuginfo))]
818                defined_at: std::panic::Location::caller(),
819            }
820        }
821    }
822
823    impl<T> From<ArcReadSignal<T>> for Signal<T, LocalStorage>
824    where
825        T: Send + Sync + 'static,
826    {
827        #[track_caller]
828        fn from(value: ArcReadSignal<T>) -> Self {
829            Self {
830                inner: ArenaItem::new_local(SignalTypes::ReadSignal(value)),
831                #[cfg(any(debug_assertions, leptos_debuginfo))]
832                defined_at: std::panic::Location::caller(),
833            }
834        }
835    }
836
837    impl<T> From<RwSignal<T>> for Signal<T>
838    where
839        T: Send + Sync + 'static,
840    {
841        #[track_caller]
842        fn from(value: RwSignal<T>) -> Self {
843            Self {
844                inner: ArenaItem::new(SignalTypes::ReadSignal(
845                    value.read_only().into(),
846                )),
847                #[cfg(any(debug_assertions, leptos_debuginfo))]
848                defined_at: std::panic::Location::caller(),
849            }
850        }
851    }
852
853    impl<T> From<MappedSignal<T>> for Signal<T>
854    where
855        T: Clone + Send + Sync + 'static,
856    {
857        #[track_caller]
858        fn from(value: MappedSignal<T>) -> Self {
859            Self::derive(move || value.get())
860        }
861    }
862
863    impl<T> From<RwSignal<T, LocalStorage>> for Signal<T, LocalStorage>
864    where
865        T: 'static,
866    {
867        #[track_caller]
868        fn from(value: RwSignal<T, LocalStorage>) -> Self {
869            Self {
870                inner: ArenaItem::new_local(SignalTypes::ReadSignal(
871                    value.read_only().into(),
872                )),
873                #[cfg(any(debug_assertions, leptos_debuginfo))]
874                defined_at: std::panic::Location::caller(),
875            }
876        }
877    }
878
879    impl<T> From<ArcRwSignal<T>> for Signal<T>
880    where
881        T: Send + Sync + 'static,
882    {
883        #[track_caller]
884        fn from(value: ArcRwSignal<T>) -> Self {
885            Self {
886                inner: ArenaItem::new(SignalTypes::ReadSignal(
887                    value.read_only(),
888                )),
889                #[cfg(any(debug_assertions, leptos_debuginfo))]
890                defined_at: std::panic::Location::caller(),
891            }
892        }
893    }
894
895    impl<T> From<ArcMappedSignal<T>> for Signal<T>
896    where
897        T: Clone + Send + Sync + 'static,
898    {
899        #[track_caller]
900        fn from(value: ArcMappedSignal<T>) -> Self {
901            MappedSignal::from(value).into()
902        }
903    }
904
905    impl<T> From<ArcRwSignal<T>> for Signal<T, LocalStorage>
906    where
907        T: Send + Sync + 'static,
908    {
909        #[track_caller]
910        fn from(value: ArcRwSignal<T>) -> Self {
911            Self {
912                inner: ArenaItem::new_local(SignalTypes::ReadSignal(
913                    value.read_only(),
914                )),
915                #[cfg(any(debug_assertions, leptos_debuginfo))]
916                defined_at: std::panic::Location::caller(),
917            }
918        }
919    }
920
921    impl<T> From<Memo<T>> for Signal<T>
922    where
923        T: Send + Sync + 'static,
924    {
925        #[track_caller]
926        fn from(value: Memo<T>) -> Self {
927            Self {
928                inner: ArenaItem::new(SignalTypes::Memo(value.into())),
929                #[cfg(any(debug_assertions, leptos_debuginfo))]
930                defined_at: std::panic::Location::caller(),
931            }
932        }
933    }
934
935    impl<T> From<Memo<T, LocalStorage>> for Signal<T, LocalStorage>
936    where
937        T: 'static,
938    {
939        #[track_caller]
940        fn from(value: Memo<T, LocalStorage>) -> Self {
941            Self {
942                inner: ArenaItem::new_local(SignalTypes::Memo(value.into())),
943                #[cfg(any(debug_assertions, leptos_debuginfo))]
944                defined_at: std::panic::Location::caller(),
945            }
946        }
947    }
948
949    impl<T> From<ArcMemo<T>> for Signal<T>
950    where
951        T: Send + Sync + 'static,
952    {
953        #[track_caller]
954        fn from(value: ArcMemo<T>) -> Self {
955            Self {
956                inner: ArenaItem::new(SignalTypes::Memo(value)),
957                #[cfg(any(debug_assertions, leptos_debuginfo))]
958                defined_at: std::panic::Location::caller(),
959            }
960        }
961    }
962
963    impl<T> From<ArcMemo<T, LocalStorage>> for Signal<T, LocalStorage>
964    where
965        T: Send + Sync + 'static,
966    {
967        #[track_caller]
968        fn from(value: ArcMemo<T, LocalStorage>) -> Self {
969            Self {
970                inner: ArenaItem::new_local(SignalTypes::Memo(value)),
971                #[cfg(any(debug_assertions, leptos_debuginfo))]
972                defined_at: std::panic::Location::caller(),
973            }
974        }
975    }
976
977    impl<T> From<T> for Signal<Option<T>>
978    where
979        T: Send + Sync + 'static,
980    {
981        #[track_caller]
982        fn from(value: T) -> Self {
983            Signal::stored(Some(value))
984        }
985    }
986
987    impl<T> From<T> for Signal<Option<T>, LocalStorage>
988    where
989        T: 'static,
990    {
991        #[track_caller]
992        fn from(value: T) -> Self {
993            Signal::stored_local(Some(value))
994        }
995    }
996
997    impl<T> From<Signal<T>> for Signal<Option<T>>
998    where
999        T: Clone + Send + Sync + 'static,
1000    {
1001        #[track_caller]
1002        fn from(value: Signal<T>) -> Self {
1003            Signal::derive(move || Some(value.get()))
1004        }
1005    }
1006
1007    impl<T> From<Signal<T, LocalStorage>> for Signal<Option<T>, LocalStorage>
1008    where
1009        T: Clone + 'static,
1010    {
1011        #[track_caller]
1012        fn from(value: Signal<T, LocalStorage>) -> Self {
1013            Signal::derive_local(move || Some(value.get()))
1014        }
1015    }
1016
1017    impl From<&str> for Signal<String> {
1018        #[track_caller]
1019        fn from(value: &str) -> Self {
1020            Signal::stored(value.to_string())
1021        }
1022    }
1023
1024    impl From<&str> for Signal<String, LocalStorage> {
1025        #[track_caller]
1026        fn from(value: &str) -> Self {
1027            Signal::stored_local(value.to_string())
1028        }
1029    }
1030
1031    impl From<&str> for Signal<Option<String>> {
1032        #[track_caller]
1033        fn from(value: &str) -> Self {
1034            Signal::stored(Some(value.to_string()))
1035        }
1036    }
1037
1038    impl From<&str> for Signal<Option<String>, LocalStorage> {
1039        #[track_caller]
1040        fn from(value: &str) -> Self {
1041            Signal::stored_local(Some(value.to_string()))
1042        }
1043    }
1044
1045    impl From<Signal<&'static str>> for Signal<String> {
1046        #[track_caller]
1047        fn from(value: Signal<&'static str>) -> Self {
1048            Signal::derive(move || value.read().to_string())
1049        }
1050    }
1051
1052    impl From<Signal<&'static str>> for Signal<String, LocalStorage> {
1053        #[track_caller]
1054        fn from(value: Signal<&'static str>) -> Self {
1055            Signal::derive_local(move || value.read().to_string())
1056        }
1057    }
1058
1059    impl From<Signal<&'static str>> for Signal<Option<String>> {
1060        #[track_caller]
1061        fn from(value: Signal<&'static str>) -> Self {
1062            Signal::derive(move || Some(value.read().to_string()))
1063        }
1064    }
1065
1066    impl From<Signal<&'static str>> for Signal<Option<String>, LocalStorage> {
1067        #[track_caller]
1068        fn from(value: Signal<&'static str>) -> Self {
1069            Signal::derive_local(move || Some(value.read().to_string()))
1070        }
1071    }
1072
1073    impl From<Signal<Option<&'static str>>> for Signal<Option<String>> {
1074        #[track_caller]
1075        fn from(value: Signal<Option<&'static str>>) -> Self {
1076            Signal::derive(move || value.read().map(str::to_string))
1077        }
1078    }
1079
1080    impl From<Signal<Option<&'static str>>>
1081        for Signal<Option<String>, LocalStorage>
1082    {
1083        #[track_caller]
1084        fn from(value: Signal<Option<&'static str>>) -> Self {
1085            Signal::derive_local(move || value.read().map(str::to_string))
1086        }
1087    }
1088
1089    #[allow(deprecated)]
1090    impl<T> From<MaybeSignal<T>> for Signal<T>
1091    where
1092        T: Send + Sync + 'static,
1093    {
1094        #[track_caller]
1095        fn from(value: MaybeSignal<T>) -> Self {
1096            match value {
1097                MaybeSignal::Static(value) => Signal::stored(value),
1098                MaybeSignal::Dynamic(signal) => signal,
1099            }
1100        }
1101    }
1102
1103    #[allow(deprecated)]
1104    impl<T> From<MaybeSignal<T, LocalStorage>> for Signal<T, LocalStorage>
1105    where
1106        T: Send + Sync + 'static,
1107    {
1108        #[track_caller]
1109        fn from(value: MaybeSignal<T, LocalStorage>) -> Self {
1110            match value {
1111                MaybeSignal::Static(value) => Signal::stored_local(value),
1112                MaybeSignal::Dynamic(signal) => signal,
1113            }
1114        }
1115    }
1116
1117    #[allow(deprecated)]
1118    impl<T> From<MaybeSignal<T>> for Signal<Option<T>>
1119    where
1120        T: Clone + Send + Sync + 'static,
1121    {
1122        #[track_caller]
1123        fn from(value: MaybeSignal<T>) -> Self {
1124            match value {
1125                MaybeSignal::Static(value) => Signal::stored(Some(value)),
1126                MaybeSignal::Dynamic(signal) => {
1127                    Signal::derive(move || Some(signal.get()))
1128                }
1129            }
1130        }
1131    }
1132
1133    #[allow(deprecated)]
1134    impl<T> From<MaybeSignal<T, LocalStorage>> for Signal<Option<T>, LocalStorage>
1135    where
1136        T: Clone + Send + Sync + 'static,
1137    {
1138        #[track_caller]
1139        fn from(value: MaybeSignal<T, LocalStorage>) -> Self {
1140            match value {
1141                MaybeSignal::Static(value) => Signal::stored_local(Some(value)),
1142                MaybeSignal::Dynamic(signal) => {
1143                    Signal::derive_local(move || Some(signal.get()))
1144                }
1145            }
1146        }
1147    }
1148
1149    impl<T> From<MaybeProp<T>> for Option<Signal<Option<T>>>
1150    where
1151        T: Send + Sync + 'static,
1152    {
1153        #[track_caller]
1154        fn from(value: MaybeProp<T>) -> Self {
1155            value.0
1156        }
1157    }
1158
1159    impl<T> From<MaybeProp<T, LocalStorage>>
1160        for Option<Signal<Option<T>, LocalStorage>>
1161    where
1162        T: Send + Sync + 'static,
1163    {
1164        #[track_caller]
1165        fn from(value: MaybeProp<T, LocalStorage>) -> Self {
1166            value.0
1167        }
1168    }
1169
1170    /// A wrapper for a value that is *either* `T` or [`Signal<T>`].
1171    ///
1172    /// This allows you to create APIs that take either a reactive or a non-reactive value
1173    /// of the same type. This is especially useful for component properties.
1174    ///
1175    /// ```
1176    /// # use reactive_graph::signal::*; let owner = reactive_graph::owner::Owner::new(); owner.set();
1177    /// # use reactive_graph::wrappers::read::MaybeSignal;
1178    /// # use reactive_graph::computed::Memo;
1179    /// # use reactive_graph::prelude::*;
1180    /// let (count, set_count) = signal(2);
1181    /// let double_count = MaybeSignal::derive(move || count.get() * 2);
1182    /// let memoized_double_count = Memo::new(move |_| count.get() * 2);
1183    /// let static_value = 5;
1184    ///
1185    /// // this function takes either a reactive or non-reactive value
1186    /// fn above_3(arg: &MaybeSignal<i32>) -> bool {
1187    ///     // ✅ calling the signal clones and returns the value
1188    ///     //    it is a shorthand for arg.get()
1189    ///     arg.get() > 3
1190    /// }
1191    ///
1192    /// assert_eq!(above_3(&static_value.into()), true);
1193    /// assert_eq!(above_3(&count.into()), false);
1194    /// assert_eq!(above_3(&double_count), true);
1195    /// assert_eq!(above_3(&memoized_double_count.into()), true);
1196    /// ```
1197    #[derive(Debug, PartialEq, Eq)]
1198    #[deprecated(
1199        since = "0.7.0-rc3",
1200        note = "`MaybeSignal<T>` is deprecated in favour of `Signal<T>` which \
1201                is `Copy`, now has a more efficient From<T> implementation \
1202                and other benefits in 0.7."
1203    )]
1204    pub enum MaybeSignal<T, S = SyncStorage>
1205    where
1206        T: 'static,
1207        S: Storage<T>,
1208    {
1209        /// An unchanging value of type `T`.
1210        Static(T),
1211        /// A reactive signal that contains a value of type `T`.
1212        Dynamic(Signal<T, S>),
1213    }
1214
1215    #[allow(deprecated)]
1216    impl<T: Clone, S> Clone for MaybeSignal<T, S>
1217    where
1218        S: Storage<T>,
1219    {
1220        fn clone(&self) -> Self {
1221            match self {
1222                Self::Static(item) => Self::Static(item.clone()),
1223                Self::Dynamic(signal) => Self::Dynamic(*signal),
1224            }
1225        }
1226    }
1227
1228    #[allow(deprecated)]
1229    impl<T: Copy, S> Copy for MaybeSignal<T, S> where S: Storage<T> {}
1230
1231    #[allow(deprecated)]
1232    impl<T: Default, S> Default for MaybeSignal<T, S>
1233    where
1234        S: Storage<T>,
1235    {
1236        fn default() -> Self {
1237            Self::Static(Default::default())
1238        }
1239    }
1240
1241    #[allow(deprecated)]
1242    impl<T, S> DefinedAt for MaybeSignal<T, S>
1243    where
1244        S: Storage<T>,
1245    {
1246        fn defined_at(&self) -> Option<&'static Location<'static>> {
1247            // TODO this could be improved, but would require moving from an enum to a struct here.
1248            // Probably not worth it for relatively small benefits.
1249            None
1250        }
1251    }
1252
1253    #[allow(deprecated)]
1254    impl<T, S> Track for MaybeSignal<T, S>
1255    where
1256        S: Storage<T> + Storage<SignalTypes<T, S>>,
1257    {
1258        fn track(&self) {
1259            match self {
1260                Self::Static(_) => {}
1261                Self::Dynamic(signal) => signal.track(),
1262            }
1263        }
1264    }
1265
1266    #[allow(deprecated)]
1267    impl<T, S> ReadUntracked for MaybeSignal<T, S>
1268    where
1269        T: Clone,
1270        S: Storage<SignalTypes<T, S>> + Storage<T>,
1271    {
1272        type Value = ReadGuard<T, SignalReadGuard<T, S>>;
1273
1274        fn try_read_untracked(&self) -> Option<Self::Value> {
1275            match self {
1276                Self::Static(t) => {
1277                    Some(ReadGuard::new(SignalReadGuard::Owned(t.clone())))
1278                }
1279                Self::Dynamic(s) => s.try_read_untracked(),
1280            }
1281        }
1282
1283        fn custom_try_read(&self) -> Option<Option<Self::Value>> {
1284            match self {
1285                Self::Static(_) => None,
1286                Self::Dynamic(s) => s.custom_try_read(),
1287            }
1288        }
1289    }
1290
1291    #[allow(deprecated)]
1292    impl<T> MaybeSignal<T>
1293    where
1294        T: Send + Sync,
1295    {
1296        /// Wraps a derived signal, i.e., any computation that accesses one or more
1297        /// reactive signals.
1298        pub fn derive(
1299            derived_signal: impl Fn() -> T + Send + Sync + 'static,
1300        ) -> Self {
1301            Self::Dynamic(Signal::derive(derived_signal))
1302        }
1303    }
1304
1305    #[allow(deprecated)]
1306    impl<T> MaybeSignal<T, LocalStorage> {
1307        /// Wraps a derived signal, i.e., any computation that accesses one or more
1308        /// reactive signals.
1309        pub fn derive_local(derived_signal: impl Fn() -> T + 'static) -> Self {
1310            Self::Dynamic(Signal::derive_local(derived_signal))
1311        }
1312    }
1313
1314    #[allow(deprecated)]
1315    impl<T> From<T> for MaybeSignal<T, SyncStorage>
1316    where
1317        SyncStorage: Storage<T>,
1318    {
1319        fn from(value: T) -> Self {
1320            Self::Static(value)
1321        }
1322    }
1323
1324    #[allow(deprecated)]
1325    impl<T> FromLocal<T> for MaybeSignal<T, LocalStorage>
1326    where
1327        LocalStorage: Storage<T>,
1328    {
1329        fn from_local(value: T) -> Self {
1330            Self::Static(value)
1331        }
1332    }
1333
1334    #[allow(deprecated)]
1335    impl<T> From<ReadSignal<T>> for MaybeSignal<T>
1336    where
1337        T: Send + Sync,
1338    {
1339        fn from(value: ReadSignal<T>) -> Self {
1340            Self::Dynamic(value.into())
1341        }
1342    }
1343
1344    #[allow(deprecated)]
1345    impl<T> From<ReadSignal<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
1346        fn from(value: ReadSignal<T, LocalStorage>) -> Self {
1347            Self::Dynamic(value.into())
1348        }
1349    }
1350
1351    #[allow(deprecated)]
1352    impl<T> From<RwSignal<T>> for MaybeSignal<T>
1353    where
1354        T: Send + Sync,
1355    {
1356        fn from(value: RwSignal<T>) -> Self {
1357            Self::Dynamic(value.into())
1358        }
1359    }
1360
1361    #[allow(deprecated)]
1362    impl<T> From<RwSignal<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
1363        fn from(value: RwSignal<T, LocalStorage>) -> Self {
1364            Self::Dynamic(value.into())
1365        }
1366    }
1367
1368    #[allow(deprecated)]
1369    impl<T> From<Memo<T>> for MaybeSignal<T>
1370    where
1371        T: Send + Sync,
1372    {
1373        fn from(value: Memo<T>) -> Self {
1374            Self::Dynamic(value.into())
1375        }
1376    }
1377
1378    #[allow(deprecated)]
1379    impl<T> From<Memo<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
1380        fn from(value: Memo<T, LocalStorage>) -> Self {
1381            Self::Dynamic(value.into())
1382        }
1383    }
1384
1385    #[allow(deprecated)]
1386    impl<T> From<ArcReadSignal<T>> for MaybeSignal<T>
1387    where
1388        T: Send + Sync,
1389    {
1390        fn from(value: ArcReadSignal<T>) -> Self {
1391            ReadSignal::from(value).into()
1392        }
1393    }
1394
1395    #[allow(deprecated)]
1396    impl<T> FromLocal<ArcReadSignal<T>> for MaybeSignal<T, LocalStorage> {
1397        fn from_local(value: ArcReadSignal<T>) -> Self {
1398            ReadSignal::from_local(value).into()
1399        }
1400    }
1401
1402    #[allow(deprecated)]
1403    impl<T> From<ArcRwSignal<T>> for MaybeSignal<T>
1404    where
1405        T: Send + Sync + 'static,
1406    {
1407        fn from(value: ArcRwSignal<T>) -> Self {
1408            RwSignal::from(value).into()
1409        }
1410    }
1411
1412    #[allow(deprecated)]
1413    impl<T> FromLocal<ArcRwSignal<T>> for MaybeSignal<T, LocalStorage>
1414    where
1415        T: 'static,
1416    {
1417        fn from_local(value: ArcRwSignal<T>) -> Self {
1418            RwSignal::from_local(value).into()
1419        }
1420    }
1421
1422    #[allow(deprecated)]
1423    impl<T> From<ArcMemo<T>> for MaybeSignal<T>
1424    where
1425        T: Send + Sync,
1426    {
1427        fn from(value: ArcMemo<T>) -> Self {
1428            Memo::from(value).into()
1429        }
1430    }
1431
1432    #[allow(deprecated)]
1433    impl<T> FromLocal<ArcMemo<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
1434        fn from_local(value: ArcMemo<T, LocalStorage>) -> Self {
1435            Memo::from_local(value).into()
1436        }
1437    }
1438
1439    #[allow(deprecated)]
1440    impl<T, S> From<Signal<T, S>> for MaybeSignal<T, S>
1441    where
1442        S: Storage<T>,
1443    {
1444        fn from(value: Signal<T, S>) -> Self {
1445            Self::Dynamic(value)
1446        }
1447    }
1448
1449    #[allow(deprecated)]
1450    impl<S> From<&str> for MaybeSignal<String, S>
1451    where
1452        S: Storage<String> + Storage<Arc<RwLock<String>>>,
1453    {
1454        fn from(value: &str) -> Self {
1455            Self::Static(value.to_string())
1456        }
1457    }
1458
1459    /// A wrapping type for an optional component prop.
1460    ///
1461    /// This can either be a signal or a non-reactive value, and may or may not have a value.
1462    /// In other words, this is an `Option<Signal<Option<T>>>`, but automatically flattens its getters.
1463    ///
1464    /// This creates an extremely flexible type for component libraries, etc.
1465    ///
1466    /// ## Examples
1467    /// ```rust
1468    /// # use reactive_graph::signal::*; let owner = reactive_graph::owner::Owner::new(); owner.set();
1469    /// # use reactive_graph::wrappers::read::MaybeProp;
1470    /// # use reactive_graph::computed::Memo;
1471    /// # use reactive_graph::prelude::*;
1472    /// let (count, set_count) = signal(Some(2));
1473    /// let double = |n| n * 2;
1474    /// let double_count = MaybeProp::derive(move || count.get().map(double));
1475    /// let memoized_double_count = Memo::new(move |_| count.get().map(double));
1476    /// let static_value = 5;
1477    ///
1478    /// // this function takes either a reactive or non-reactive value
1479    /// fn above_3(arg: &MaybeProp<i32>) -> bool {
1480    ///     // ✅ calling the signal clones and returns the value
1481    ///     //    it is a shorthand for arg.get()q
1482    ///     arg.get().map(|arg| arg > 3).unwrap_or(false)
1483    /// }
1484    ///
1485    /// assert_eq!(above_3(&None::<i32>.into()), false);
1486    /// assert_eq!(above_3(&static_value.into()), true);
1487    /// assert_eq!(above_3(&count.into()), false);
1488    /// assert_eq!(above_3(&double_count), true);
1489    /// assert_eq!(above_3(&memoized_double_count.into()), true);
1490    /// ```
1491    #[derive(Debug, PartialEq, Eq)]
1492    pub struct MaybeProp<T: 'static, S = SyncStorage>(
1493        pub(crate) Option<Signal<Option<T>, S>>,
1494    )
1495    where
1496        S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>;
1497
1498    impl<T, S> Clone for MaybeProp<T, S>
1499    where
1500        S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
1501    {
1502        fn clone(&self) -> Self {
1503            *self
1504        }
1505    }
1506
1507    impl<T, S> Copy for MaybeProp<T, S> where
1508        S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>
1509    {
1510    }
1511
1512    impl<T, S> Default for MaybeProp<T, S>
1513    where
1514        S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
1515    {
1516        fn default() -> Self {
1517            Self(None)
1518        }
1519    }
1520
1521    impl<T, S> DefinedAt for MaybeProp<T, S>
1522    where
1523        S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
1524    {
1525        fn defined_at(&self) -> Option<&'static Location<'static>> {
1526            // TODO this can be improved by adding a defined_at field
1527            None
1528        }
1529    }
1530
1531    impl<T, S> Track for MaybeProp<T, S>
1532    where
1533        S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
1534    {
1535        fn track(&self) {
1536            match &self.0 {
1537                None => {}
1538                Some(signal) => signal.track(),
1539            }
1540        }
1541    }
1542
1543    impl<T, S> ReadUntracked for MaybeProp<T, S>
1544    where
1545        S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
1546    {
1547        type Value = ReadGuard<Option<T>, SignalReadGuard<Option<T>, S>>;
1548
1549        fn try_read_untracked(&self) -> Option<Self::Value> {
1550            match &self.0 {
1551                None => Some(ReadGuard::new(SignalReadGuard::Owned(None))),
1552                Some(inner) => inner.try_read_untracked(),
1553            }
1554        }
1555
1556        fn custom_try_read(&self) -> Option<Option<Self::Value>> {
1557            match &self.0 {
1558                None => None,
1559                Some(inner) => inner.custom_try_read(),
1560            }
1561        }
1562    }
1563
1564    impl<T> MaybeProp<T>
1565    where
1566        T: Send + Sync,
1567    {
1568        /// Wraps a derived signal, i.e., any computation that accesses one or more
1569        /// reactive signals.
1570        pub fn derive(
1571            derived_signal: impl Fn() -> Option<T> + Send + Sync + 'static,
1572        ) -> Self {
1573            Self(Some(Signal::derive(derived_signal)))
1574        }
1575    }
1576
1577    impl<T> From<T> for MaybeProp<T>
1578    where
1579        T: Send + Sync,
1580        SyncStorage: Storage<Option<T>>,
1581    {
1582        fn from(value: T) -> Self {
1583            Self(Some(Signal::stored(Some(value))))
1584        }
1585    }
1586
1587    impl<T> From<Option<T>> for MaybeProp<T>
1588    where
1589        T: Send + Sync,
1590        SyncStorage: Storage<Option<T>>,
1591    {
1592        fn from(value: Option<T>) -> Self {
1593            Self(Some(Signal::stored(value)))
1594        }
1595    }
1596
1597    #[allow(deprecated)]
1598    impl<T> From<MaybeSignal<Option<T>>> for MaybeProp<T>
1599    where
1600        T: Send + Sync,
1601        SyncStorage: Storage<Option<T>>,
1602    {
1603        fn from(value: MaybeSignal<Option<T>>) -> Self {
1604            Self(Some(value.into()))
1605        }
1606    }
1607
1608    #[allow(deprecated)]
1609    impl<T> From<Option<MaybeSignal<Option<T>>>> for MaybeProp<T>
1610    where
1611        T: Send + Sync,
1612        SyncStorage: Storage<Option<T>>,
1613    {
1614        fn from(value: Option<MaybeSignal<Option<T>>>) -> Self {
1615            Self(value.map(Into::into))
1616        }
1617    }
1618
1619    impl<T> From<ReadSignal<Option<T>>> for MaybeProp<T>
1620    where
1621        T: Send + Sync,
1622    {
1623        fn from(value: ReadSignal<Option<T>>) -> Self {
1624            Self(Some(value.into()))
1625        }
1626    }
1627
1628    impl<T> From<RwSignal<Option<T>>> for MaybeProp<T>
1629    where
1630        T: Send + Sync,
1631    {
1632        fn from(value: RwSignal<Option<T>>) -> Self {
1633            Self(Some(value.into()))
1634        }
1635    }
1636
1637    impl<T> From<Memo<Option<T>>> for MaybeProp<T>
1638    where
1639        T: Send + Sync,
1640    {
1641        fn from(value: Memo<Option<T>>) -> Self {
1642            Self(Some(value.into()))
1643        }
1644    }
1645
1646    impl<T> From<Signal<Option<T>>> for MaybeProp<T>
1647    where
1648        T: Send + Sync,
1649        SyncStorage: Storage<Option<T>>,
1650    {
1651        fn from(value: Signal<Option<T>>) -> Self {
1652            Self(Some(value))
1653        }
1654    }
1655
1656    impl<T> From<ReadSignal<T>> for MaybeProp<T>
1657    where
1658        T: Send + Sync + Clone,
1659    {
1660        fn from(value: ReadSignal<T>) -> Self {
1661            Self(Some(Signal::derive(move || Some(value.get()))))
1662        }
1663    }
1664
1665    impl<T> From<RwSignal<T>> for MaybeProp<T>
1666    where
1667        T: Send + Sync + Clone,
1668    {
1669        fn from(value: RwSignal<T>) -> Self {
1670            Self(Some(Signal::derive(move || Some(value.get()))))
1671        }
1672    }
1673
1674    impl<T> From<Memo<T>> for MaybeProp<T>
1675    where
1676        T: Send + Sync + Clone,
1677    {
1678        fn from(value: Memo<T>) -> Self {
1679            Self(Some(Signal::derive(move || Some(value.get()))))
1680        }
1681    }
1682
1683    impl<T> From<Signal<T>> for MaybeProp<T>
1684    where
1685        T: Send + Sync + Clone,
1686    {
1687        fn from(value: Signal<T>) -> Self {
1688            Self(Some(Signal::derive(move || Some(value.get()))))
1689        }
1690    }
1691
1692    impl From<&str> for MaybeProp<String> {
1693        fn from(value: &str) -> Self {
1694            Self(Some(Signal::from(Some(value.to_string()))))
1695        }
1696    }
1697
1698    impl<T> MaybeProp<T, LocalStorage> {
1699        /// Wraps a derived signal, i.e., any computation that accesses one or more
1700        /// reactive signals.
1701        pub fn derive_local(
1702            derived_signal: impl Fn() -> Option<T> + 'static,
1703        ) -> Self {
1704            Self(Some(Signal::derive_local(derived_signal)))
1705        }
1706    }
1707
1708    impl<T> FromLocal<T> for MaybeProp<T, LocalStorage> {
1709        fn from_local(value: T) -> Self {
1710            Self(Some(Signal::stored_local(Some(value))))
1711        }
1712    }
1713
1714    impl<T> FromLocal<Option<T>> for MaybeProp<T, LocalStorage> {
1715        fn from_local(value: Option<T>) -> Self {
1716            Self(Some(Signal::stored_local(value)))
1717        }
1718    }
1719
1720    #[allow(deprecated)]
1721    impl<T> From<MaybeSignal<Option<T>, LocalStorage>>
1722        for MaybeProp<T, LocalStorage>
1723    where
1724        T: Send + Sync,
1725    {
1726        fn from(value: MaybeSignal<Option<T>, LocalStorage>) -> Self {
1727            Self(Some(value.into()))
1728        }
1729    }
1730
1731    #[allow(deprecated)]
1732    impl<T> From<Option<MaybeSignal<Option<T>, LocalStorage>>>
1733        for MaybeProp<T, LocalStorage>
1734    where
1735        T: Send + Sync,
1736    {
1737        fn from(value: Option<MaybeSignal<Option<T>, LocalStorage>>) -> Self {
1738            Self(value.map(Into::into))
1739        }
1740    }
1741
1742    impl<T> From<ReadSignal<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage>
1743    where
1744        T: Send + Sync,
1745    {
1746        fn from(value: ReadSignal<Option<T>, LocalStorage>) -> Self {
1747            Self(Some(value.into()))
1748        }
1749    }
1750
1751    impl<T> From<RwSignal<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage>
1752    where
1753        T: Send + Sync,
1754    {
1755        fn from(value: RwSignal<Option<T>, LocalStorage>) -> Self {
1756            Self(Some(value.into()))
1757        }
1758    }
1759
1760    impl<T> From<Memo<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage>
1761    where
1762        T: Send + Sync,
1763    {
1764        fn from(value: Memo<Option<T>, LocalStorage>) -> Self {
1765            Self(Some(value.into()))
1766        }
1767    }
1768
1769    impl<T> From<Signal<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage> {
1770        fn from(value: Signal<Option<T>, LocalStorage>) -> Self {
1771            Self(Some(value))
1772        }
1773    }
1774
1775    impl<T> From<ReadSignal<T, LocalStorage>> for MaybeProp<T, LocalStorage>
1776    where
1777        T: Send + Sync + Clone,
1778    {
1779        fn from(value: ReadSignal<T, LocalStorage>) -> Self {
1780            Self(Some(Signal::derive_local(move || Some(value.get()))))
1781        }
1782    }
1783
1784    impl<T> From<RwSignal<T, LocalStorage>> for MaybeProp<T, LocalStorage>
1785    where
1786        T: Send + Sync + Clone,
1787    {
1788        fn from(value: RwSignal<T, LocalStorage>) -> Self {
1789            Self(Some(Signal::derive_local(move || Some(value.get()))))
1790        }
1791    }
1792
1793    impl<T> From<Memo<T, LocalStorage>> for MaybeProp<T, LocalStorage>
1794    where
1795        T: Send + Sync + Clone,
1796    {
1797        fn from(value: Memo<T, LocalStorage>) -> Self {
1798            Self(Some(Signal::derive_local(move || Some(value.get()))))
1799        }
1800    }
1801
1802    impl<T> From<Signal<T, LocalStorage>> for MaybeProp<T, LocalStorage>
1803    where
1804        T: Send + Sync + Clone,
1805    {
1806        fn from(value: Signal<T, LocalStorage>) -> Self {
1807            Self(Some(Signal::derive_local(move || Some(value.get()))))
1808        }
1809    }
1810
1811    impl From<&str> for MaybeProp<String, LocalStorage> {
1812        fn from(value: &str) -> Self {
1813            Self(Some(Signal::stored_local(Some(value.to_string()))))
1814        }
1815    }
1816
1817    /// The content of a [`Signal`] wrapper read guard, variable depending on the signal type.
1818    pub enum SignalReadGuard<T: 'static, S: Storage<T>> {
1819        /// A read signal guard.
1820        Read(ReadGuard<T, Plain<T>>),
1821        #[allow(clippy::type_complexity)]
1822        /// A memo guard.
1823        Memo(
1824            ReadGuard<T, Mapped<Plain<Option<<S as Storage<T>>::Wrapped>>, T>>,
1825        ),
1826        /// A fake guard for derived signals, the content had to actually be cloned, so it's not a guard but we pretend it is.
1827        Owned(T),
1828    }
1829
1830    impl<T: 'static + std::fmt::Debug, S: Storage<T> + std::fmt::Debug>
1831        std::fmt::Debug for SignalReadGuard<T, S>
1832    where
1833        <S as Storage<T>>::Wrapped: std::fmt::Debug,
1834    {
1835        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1836            match self {
1837                Self::Read(arg0) => f.debug_tuple("Read").field(arg0).finish(),
1838                Self::Memo(arg0) => f.debug_tuple("Memo").field(arg0).finish(),
1839                Self::Owned(arg0) => {
1840                    f.debug_tuple("Owned").field(arg0).finish()
1841                }
1842            }
1843        }
1844    }
1845
1846    impl<T, S> Clone for SignalReadGuard<T, S>
1847    where
1848        S: Storage<T>,
1849        T: Clone,
1850        Plain<T>: Clone,
1851        Mapped<Plain<Option<<S as Storage<T>>::Wrapped>>, T>: Clone,
1852    {
1853        fn clone(&self) -> Self {
1854            match self {
1855                SignalReadGuard::Read(i) => SignalReadGuard::Read(i.clone()),
1856                SignalReadGuard::Memo(i) => SignalReadGuard::Memo(i.clone()),
1857                SignalReadGuard::Owned(i) => SignalReadGuard::Owned(i.clone()),
1858            }
1859        }
1860    }
1861
1862    impl<T, S> Deref for SignalReadGuard<T, S>
1863    where
1864        S: Storage<T>,
1865    {
1866        type Target = T;
1867        fn deref(&self) -> &Self::Target {
1868            match self {
1869                SignalReadGuard::Read(i) => i,
1870                SignalReadGuard::Memo(i) => i,
1871                SignalReadGuard::Owned(i) => i,
1872            }
1873        }
1874    }
1875
1876    impl<T, S> Borrow<T> for SignalReadGuard<T, S>
1877    where
1878        S: Storage<T>,
1879    {
1880        fn borrow(&self) -> &T {
1881            self.deref()
1882        }
1883    }
1884
1885    impl<T, S> PartialEq<T> for SignalReadGuard<T, S>
1886    where
1887        S: Storage<T>,
1888        T: PartialEq,
1889    {
1890        fn eq(&self, other: &T) -> bool {
1891            self.deref() == other
1892        }
1893    }
1894
1895    impl<T, S> Display for SignalReadGuard<T, S>
1896    where
1897        S: Storage<T>,
1898        T: Display,
1899    {
1900        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1901            Display::fmt(&**self, f)
1902        }
1903    }
1904}
1905
1906/// Types that abstract over the ability to update a signal.
1907pub mod write {
1908    use crate::{
1909        owner::{ArenaItem, Storage, SyncStorage},
1910        signal::{ArcRwSignal, ArcWriteSignal, RwSignal, WriteSignal},
1911        traits::Set,
1912    };
1913
1914    /// Helper trait for converting `Fn(T)` into [`SignalSetter<T>`].
1915    pub trait IntoSignalSetter<T, S>: Sized {
1916        /// Consumes `self`, returning [`SignalSetter<T>`].
1917        fn into_signal_setter(self) -> SignalSetter<T, S>;
1918    }
1919
1920    impl<F, T, S> IntoSignalSetter<T, S> for F
1921    where
1922        F: Fn(T) + 'static + Send + Sync,
1923        S: Storage<Box<dyn Fn(T) + Send + Sync>>,
1924    {
1925        fn into_signal_setter(self) -> SignalSetter<T, S> {
1926            SignalSetter::map(self)
1927        }
1928    }
1929
1930    /// A wrapper for any kind of settable reactive signal: a [`WriteSignal`],
1931    /// [`RwSignal`], or closure that receives a value and sets a signal depending
1932    /// on it.
1933    ///
1934    /// This allows you to create APIs that take any kind of `SignalSetter<T>` as an argument,
1935    /// rather than adding a generic `F: Fn(T)`. Values can be set with the same
1936    /// function call or `set()`, API as other signals.
1937    ///
1938    /// ## Core Trait Implementations
1939    /// - [`.set()`](#impl-SignalSet<T>-for-SignalSetter<T>) (or calling the setter as a function)
1940    ///   sets the signal’s value, and notifies all subscribers that the signal’s value has changed.
1941    ///   to subscribe to the signal, and to re-run whenever the value of the signal changes.
1942    ///
1943    /// ## Examples
1944    /// ```rust
1945    /// # use reactive_graph::prelude::*;  let owner = reactive_graph::owner::Owner::new(); owner.set();
1946    /// # use reactive_graph::wrappers::write::SignalSetter;
1947    /// # use reactive_graph::signal::signal;
1948    /// let (count, set_count) = signal(2);
1949    /// let set_double_input = SignalSetter::map(move |n| set_count.set(n * 2));
1950    ///
1951    /// // this function takes any kind of signal setter
1952    /// fn set_to_4(setter: &SignalSetter<i32>) {
1953    ///     // ✅ calling the signal sets the value
1954    ///     //    can be `setter(4)` on nightly
1955    ///     setter.set(4);
1956    /// }
1957    ///
1958    /// set_to_4(&set_count.into());
1959    /// assert_eq!(count.get(), 4);
1960    /// set_to_4(&set_double_input);
1961    /// assert_eq!(count.get(), 8);
1962    /// ```
1963    #[derive(Debug, PartialEq, Eq)]
1964    pub struct SignalSetter<T, S = SyncStorage>
1965    where
1966        T: 'static,
1967    {
1968        inner: SignalSetterTypes<T, S>,
1969        #[cfg(any(debug_assertions, leptos_debuginfo))]
1970        defined_at: &'static std::panic::Location<'static>,
1971    }
1972
1973    impl<T, S> Clone for SignalSetter<T, S> {
1974        fn clone(&self) -> Self {
1975            *self
1976        }
1977    }
1978
1979    impl<T: Default + 'static, S> Default for SignalSetter<T, S> {
1980        #[track_caller]
1981        fn default() -> Self {
1982            Self {
1983                inner: SignalSetterTypes::Default,
1984                #[cfg(any(debug_assertions, leptos_debuginfo))]
1985                defined_at: std::panic::Location::caller(),
1986            }
1987        }
1988    }
1989
1990    impl<T, S> Copy for SignalSetter<T, S> {}
1991
1992    impl<T, S> Set for SignalSetter<T, S>
1993    where
1994        T: 'static,
1995        S: Storage<ArcWriteSignal<T>> + Storage<Box<dyn Fn(T) + Send + Sync>>,
1996    {
1997        type Value = T;
1998
1999        fn set(&self, new_value: Self::Value) {
2000            match self.inner {
2001                SignalSetterTypes::Default => {}
2002                SignalSetterTypes::Write(w) => w.set(new_value),
2003                SignalSetterTypes::Mapped(s) => {
2004                    s.try_with_value(|setter| setter(new_value));
2005                }
2006            }
2007        }
2008
2009        fn try_set(&self, new_value: Self::Value) -> Option<Self::Value> {
2010            match self.inner {
2011                SignalSetterTypes::Default => Some(new_value),
2012                SignalSetterTypes::Write(w) => w.try_set(new_value),
2013                SignalSetterTypes::Mapped(s) => {
2014                    let mut new_value = Some(new_value);
2015
2016                    let _ = s.try_with_value(|setter| {
2017                        setter(new_value.take().unwrap())
2018                    });
2019
2020                    new_value
2021                }
2022            }
2023        }
2024    }
2025
2026    impl<T, S> SignalSetter<T, S>
2027    where
2028        S: Storage<Box<dyn Fn(T) + Send + Sync>>,
2029    {
2030        /// Wraps a signal-setting closure, i.e., any computation that sets one or more reactive signals.
2031        #[track_caller]
2032        pub fn map(mapped_setter: impl Fn(T) + Send + Sync + 'static) -> Self {
2033            Self {
2034                inner: SignalSetterTypes::Mapped(ArenaItem::new_with_storage(
2035                    Box::new(mapped_setter),
2036                )),
2037                #[cfg(any(debug_assertions, leptos_debuginfo))]
2038                defined_at: std::panic::Location::caller(),
2039            }
2040        }
2041    }
2042
2043    impl<T, S> From<WriteSignal<T, S>> for SignalSetter<T, S> {
2044        #[track_caller]
2045        fn from(value: WriteSignal<T, S>) -> Self {
2046            Self {
2047                inner: SignalSetterTypes::Write(value),
2048                #[cfg(any(debug_assertions, leptos_debuginfo))]
2049                defined_at: std::panic::Location::caller(),
2050            }
2051        }
2052    }
2053
2054    impl<T, S> From<RwSignal<T, S>> for SignalSetter<T, S>
2055    where
2056        T: Send + Sync + 'static,
2057        S: Storage<ArcRwSignal<T>> + Storage<ArcWriteSignal<T>>,
2058    {
2059        #[track_caller]
2060        fn from(value: RwSignal<T, S>) -> Self {
2061            Self {
2062                inner: SignalSetterTypes::Write(value.write_only()),
2063                #[cfg(any(debug_assertions, leptos_debuginfo))]
2064                defined_at: std::panic::Location::caller(),
2065            }
2066        }
2067    }
2068
2069    enum SignalSetterTypes<T, S = SyncStorage>
2070    where
2071        T: 'static,
2072    {
2073        Write(WriteSignal<T, S>),
2074        Mapped(ArenaItem<Box<dyn Fn(T) + Send + Sync>, S>),
2075        Default,
2076    }
2077
2078    impl<T, S> Clone for SignalSetterTypes<T, S> {
2079        fn clone(&self) -> Self {
2080            *self
2081        }
2082    }
2083
2084    impl<T, S> Copy for SignalSetterTypes<T, S> {}
2085
2086    impl<T, S> core::fmt::Debug for SignalSetterTypes<T, S>
2087    where
2088        T: core::fmt::Debug,
2089        S: core::fmt::Debug,
2090    {
2091        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2092            match self {
2093                Self::Write(arg0) => {
2094                    f.debug_tuple("WriteSignal").field(arg0).finish()
2095                }
2096                Self::Mapped(_) => f.debug_tuple("Mapped").finish(),
2097                Self::Default => {
2098                    f.debug_tuple("SignalSetter<Default>").finish()
2099                }
2100            }
2101        }
2102    }
2103
2104    impl<T, S> PartialEq for SignalSetterTypes<T, S>
2105    where
2106        T: PartialEq,
2107    {
2108        fn eq(&self, other: &Self) -> bool {
2109            match (self, other) {
2110                (Self::Write(l0), Self::Write(r0)) => l0 == r0,
2111                (Self::Mapped(l0), Self::Mapped(r0)) => std::ptr::eq(l0, r0),
2112                _ => false,
2113            }
2114        }
2115    }
2116
2117    impl<T, S> Eq for SignalSetterTypes<T, S> where T: PartialEq {}
2118}