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        T: Clone,
1546        S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
1547    {
1548        type Value = ReadGuard<Option<T>, SignalReadGuard<Option<T>, S>>;
1549
1550        fn try_read_untracked(&self) -> Option<Self::Value> {
1551            match &self.0 {
1552                None => Some(ReadGuard::new(SignalReadGuard::Owned(None))),
1553                Some(inner) => inner.try_read_untracked(),
1554            }
1555        }
1556
1557        fn custom_try_read(&self) -> Option<Option<Self::Value>> {
1558            match &self.0 {
1559                None => None,
1560                Some(inner) => inner.custom_try_read(),
1561            }
1562        }
1563    }
1564
1565    impl<T> MaybeProp<T>
1566    where
1567        T: Send + Sync,
1568    {
1569        /// Wraps a derived signal, i.e., any computation that accesses one or more
1570        /// reactive signals.
1571        pub fn derive(
1572            derived_signal: impl Fn() -> Option<T> + Send + Sync + 'static,
1573        ) -> Self {
1574            Self(Some(Signal::derive(derived_signal)))
1575        }
1576    }
1577
1578    impl<T> From<T> for MaybeProp<T>
1579    where
1580        T: Send + Sync,
1581        SyncStorage: Storage<Option<T>>,
1582    {
1583        fn from(value: T) -> Self {
1584            Self(Some(Signal::stored(Some(value))))
1585        }
1586    }
1587
1588    impl<T> From<Option<T>> for MaybeProp<T>
1589    where
1590        T: Send + Sync,
1591        SyncStorage: Storage<Option<T>>,
1592    {
1593        fn from(value: Option<T>) -> Self {
1594            Self(Some(Signal::stored(value)))
1595        }
1596    }
1597
1598    #[allow(deprecated)]
1599    impl<T> From<MaybeSignal<Option<T>>> for MaybeProp<T>
1600    where
1601        T: Send + Sync,
1602        SyncStorage: Storage<Option<T>>,
1603    {
1604        fn from(value: MaybeSignal<Option<T>>) -> Self {
1605            Self(Some(value.into()))
1606        }
1607    }
1608
1609    #[allow(deprecated)]
1610    impl<T> From<Option<MaybeSignal<Option<T>>>> for MaybeProp<T>
1611    where
1612        T: Send + Sync,
1613        SyncStorage: Storage<Option<T>>,
1614    {
1615        fn from(value: Option<MaybeSignal<Option<T>>>) -> Self {
1616            Self(value.map(Into::into))
1617        }
1618    }
1619
1620    impl<T> From<ReadSignal<Option<T>>> for MaybeProp<T>
1621    where
1622        T: Send + Sync,
1623    {
1624        fn from(value: ReadSignal<Option<T>>) -> Self {
1625            Self(Some(value.into()))
1626        }
1627    }
1628
1629    impl<T> From<RwSignal<Option<T>>> for MaybeProp<T>
1630    where
1631        T: Send + Sync,
1632    {
1633        fn from(value: RwSignal<Option<T>>) -> Self {
1634            Self(Some(value.into()))
1635        }
1636    }
1637
1638    impl<T> From<Memo<Option<T>>> for MaybeProp<T>
1639    where
1640        T: Send + Sync,
1641    {
1642        fn from(value: Memo<Option<T>>) -> Self {
1643            Self(Some(value.into()))
1644        }
1645    }
1646
1647    impl<T> From<Signal<Option<T>>> for MaybeProp<T>
1648    where
1649        T: Send + Sync,
1650        SyncStorage: Storage<Option<T>>,
1651    {
1652        fn from(value: Signal<Option<T>>) -> Self {
1653            Self(Some(value))
1654        }
1655    }
1656
1657    impl<T> From<ReadSignal<T>> for MaybeProp<T>
1658    where
1659        T: Send + Sync + Clone,
1660    {
1661        fn from(value: ReadSignal<T>) -> Self {
1662            Self(Some(Signal::derive(move || Some(value.get()))))
1663        }
1664    }
1665
1666    impl<T> From<RwSignal<T>> for MaybeProp<T>
1667    where
1668        T: Send + Sync + Clone,
1669    {
1670        fn from(value: RwSignal<T>) -> Self {
1671            Self(Some(Signal::derive(move || Some(value.get()))))
1672        }
1673    }
1674
1675    impl<T> From<Memo<T>> for MaybeProp<T>
1676    where
1677        T: Send + Sync + Clone,
1678    {
1679        fn from(value: Memo<T>) -> Self {
1680            Self(Some(Signal::derive(move || Some(value.get()))))
1681        }
1682    }
1683
1684    impl<T> From<Signal<T>> for MaybeProp<T>
1685    where
1686        T: Send + Sync + Clone,
1687    {
1688        fn from(value: Signal<T>) -> Self {
1689            Self(Some(Signal::derive(move || Some(value.get()))))
1690        }
1691    }
1692
1693    impl From<&str> for MaybeProp<String> {
1694        fn from(value: &str) -> Self {
1695            Self(Some(Signal::from(Some(value.to_string()))))
1696        }
1697    }
1698
1699    impl<T> MaybeProp<T, LocalStorage> {
1700        /// Wraps a derived signal, i.e., any computation that accesses one or more
1701        /// reactive signals.
1702        pub fn derive_local(
1703            derived_signal: impl Fn() -> Option<T> + 'static,
1704        ) -> Self {
1705            Self(Some(Signal::derive_local(derived_signal)))
1706        }
1707    }
1708
1709    impl<T> FromLocal<T> for MaybeProp<T, LocalStorage> {
1710        fn from_local(value: T) -> Self {
1711            Self(Some(Signal::stored_local(Some(value))))
1712        }
1713    }
1714
1715    impl<T> FromLocal<Option<T>> for MaybeProp<T, LocalStorage> {
1716        fn from_local(value: Option<T>) -> Self {
1717            Self(Some(Signal::stored_local(value)))
1718        }
1719    }
1720
1721    #[allow(deprecated)]
1722    impl<T> From<MaybeSignal<Option<T>, LocalStorage>>
1723        for MaybeProp<T, LocalStorage>
1724    where
1725        T: Send + Sync,
1726    {
1727        fn from(value: MaybeSignal<Option<T>, LocalStorage>) -> Self {
1728            Self(Some(value.into()))
1729        }
1730    }
1731
1732    #[allow(deprecated)]
1733    impl<T> From<Option<MaybeSignal<Option<T>, LocalStorage>>>
1734        for MaybeProp<T, LocalStorage>
1735    where
1736        T: Send + Sync,
1737    {
1738        fn from(value: Option<MaybeSignal<Option<T>, LocalStorage>>) -> Self {
1739            Self(value.map(Into::into))
1740        }
1741    }
1742
1743    impl<T> From<ReadSignal<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage>
1744    where
1745        T: Send + Sync,
1746    {
1747        fn from(value: ReadSignal<Option<T>, LocalStorage>) -> Self {
1748            Self(Some(value.into()))
1749        }
1750    }
1751
1752    impl<T> From<RwSignal<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage>
1753    where
1754        T: Send + Sync,
1755    {
1756        fn from(value: RwSignal<Option<T>, LocalStorage>) -> Self {
1757            Self(Some(value.into()))
1758        }
1759    }
1760
1761    impl<T> From<Memo<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage>
1762    where
1763        T: Send + Sync,
1764    {
1765        fn from(value: Memo<Option<T>, LocalStorage>) -> Self {
1766            Self(Some(value.into()))
1767        }
1768    }
1769
1770    impl<T> From<Signal<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage> {
1771        fn from(value: Signal<Option<T>, LocalStorage>) -> Self {
1772            Self(Some(value))
1773        }
1774    }
1775
1776    impl<T> From<ReadSignal<T, LocalStorage>> for MaybeProp<T, LocalStorage>
1777    where
1778        T: Send + Sync + Clone,
1779    {
1780        fn from(value: ReadSignal<T, LocalStorage>) -> Self {
1781            Self(Some(Signal::derive_local(move || Some(value.get()))))
1782        }
1783    }
1784
1785    impl<T> From<RwSignal<T, LocalStorage>> for MaybeProp<T, LocalStorage>
1786    where
1787        T: Send + Sync + Clone,
1788    {
1789        fn from(value: RwSignal<T, LocalStorage>) -> Self {
1790            Self(Some(Signal::derive_local(move || Some(value.get()))))
1791        }
1792    }
1793
1794    impl<T> From<Memo<T, LocalStorage>> for MaybeProp<T, LocalStorage>
1795    where
1796        T: Send + Sync + Clone,
1797    {
1798        fn from(value: Memo<T, LocalStorage>) -> Self {
1799            Self(Some(Signal::derive_local(move || Some(value.get()))))
1800        }
1801    }
1802
1803    impl<T> From<Signal<T, LocalStorage>> for MaybeProp<T, LocalStorage>
1804    where
1805        T: Send + Sync + Clone,
1806    {
1807        fn from(value: Signal<T, LocalStorage>) -> Self {
1808            Self(Some(Signal::derive_local(move || Some(value.get()))))
1809        }
1810    }
1811
1812    impl From<&str> for MaybeProp<String, LocalStorage> {
1813        fn from(value: &str) -> Self {
1814            Self(Some(Signal::stored_local(Some(value.to_string()))))
1815        }
1816    }
1817
1818    /// The content of a [`Signal`] wrapper read guard, variable depending on the signal type.
1819    pub enum SignalReadGuard<T: 'static, S: Storage<T>> {
1820        /// A read signal guard.
1821        Read(ReadGuard<T, Plain<T>>),
1822        #[allow(clippy::type_complexity)]
1823        /// A memo guard.
1824        Memo(
1825            ReadGuard<T, Mapped<Plain<Option<<S as Storage<T>>::Wrapped>>, T>>,
1826        ),
1827        /// A fake guard for derived signals, the content had to actually be cloned, so it's not a guard but we pretend it is.
1828        Owned(T),
1829    }
1830
1831    impl<T: 'static + std::fmt::Debug, S: Storage<T> + std::fmt::Debug>
1832        std::fmt::Debug for SignalReadGuard<T, S>
1833    where
1834        <S as Storage<T>>::Wrapped: std::fmt::Debug,
1835    {
1836        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1837            match self {
1838                Self::Read(arg0) => f.debug_tuple("Read").field(arg0).finish(),
1839                Self::Memo(arg0) => f.debug_tuple("Memo").field(arg0).finish(),
1840                Self::Owned(arg0) => {
1841                    f.debug_tuple("Owned").field(arg0).finish()
1842                }
1843            }
1844        }
1845    }
1846
1847    impl<T, S> Clone for SignalReadGuard<T, S>
1848    where
1849        S: Storage<T>,
1850        T: Clone,
1851        Plain<T>: Clone,
1852        Mapped<Plain<Option<<S as Storage<T>>::Wrapped>>, T>: Clone,
1853    {
1854        fn clone(&self) -> Self {
1855            match self {
1856                SignalReadGuard::Read(i) => SignalReadGuard::Read(i.clone()),
1857                SignalReadGuard::Memo(i) => SignalReadGuard::Memo(i.clone()),
1858                SignalReadGuard::Owned(i) => SignalReadGuard::Owned(i.clone()),
1859            }
1860        }
1861    }
1862
1863    impl<T, S> Deref for SignalReadGuard<T, S>
1864    where
1865        S: Storage<T>,
1866    {
1867        type Target = T;
1868        fn deref(&self) -> &Self::Target {
1869            match self {
1870                SignalReadGuard::Read(i) => i,
1871                SignalReadGuard::Memo(i) => i,
1872                SignalReadGuard::Owned(i) => i,
1873            }
1874        }
1875    }
1876
1877    impl<T, S> Borrow<T> for SignalReadGuard<T, S>
1878    where
1879        S: Storage<T>,
1880    {
1881        fn borrow(&self) -> &T {
1882            self.deref()
1883        }
1884    }
1885
1886    impl<T, S> PartialEq<T> for SignalReadGuard<T, S>
1887    where
1888        S: Storage<T>,
1889        T: PartialEq,
1890    {
1891        fn eq(&self, other: &T) -> bool {
1892            self.deref() == other
1893        }
1894    }
1895
1896    impl<T, S> Display for SignalReadGuard<T, S>
1897    where
1898        S: Storage<T>,
1899        T: Display,
1900    {
1901        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1902            Display::fmt(&**self, f)
1903        }
1904    }
1905}
1906
1907/// Types that abstract over the ability to update a signal.
1908pub mod write {
1909    use crate::{
1910        owner::{ArenaItem, Storage, SyncStorage},
1911        signal::{ArcRwSignal, ArcWriteSignal, RwSignal, WriteSignal},
1912        traits::Set,
1913    };
1914
1915    /// Helper trait for converting `Fn(T)` into [`SignalSetter<T>`].
1916    pub trait IntoSignalSetter<T, S>: Sized {
1917        /// Consumes `self`, returning [`SignalSetter<T>`].
1918        fn into_signal_setter(self) -> SignalSetter<T, S>;
1919    }
1920
1921    impl<F, T, S> IntoSignalSetter<T, S> for F
1922    where
1923        F: Fn(T) + 'static + Send + Sync,
1924        S: Storage<Box<dyn Fn(T) + Send + Sync>>,
1925    {
1926        fn into_signal_setter(self) -> SignalSetter<T, S> {
1927            SignalSetter::map(self)
1928        }
1929    }
1930
1931    /// A wrapper for any kind of settable reactive signal: a [`WriteSignal`],
1932    /// [`RwSignal`], or closure that receives a value and sets a signal depending
1933    /// on it.
1934    ///
1935    /// This allows you to create APIs that take any kind of `SignalSetter<T>` as an argument,
1936    /// rather than adding a generic `F: Fn(T)`. Values can be set with the same
1937    /// function call or `set()`, API as other signals.
1938    ///
1939    /// ## Core Trait Implementations
1940    /// - [`.set()`](#impl-SignalSet<T>-for-SignalSetter<T>) (or calling the setter as a function)
1941    ///   sets the signal’s value, and notifies all subscribers that the signal’s value has changed.
1942    ///   to subscribe to the signal, and to re-run whenever the value of the signal changes.
1943    ///
1944    /// ## Examples
1945    /// ```rust
1946    /// # use reactive_graph::prelude::*;  let owner = reactive_graph::owner::Owner::new(); owner.set();
1947    /// # use reactive_graph::wrappers::write::SignalSetter;
1948    /// # use reactive_graph::signal::signal;
1949    /// let (count, set_count) = signal(2);
1950    /// let set_double_input = SignalSetter::map(move |n| set_count.set(n * 2));
1951    ///
1952    /// // this function takes any kind of signal setter
1953    /// fn set_to_4(setter: &SignalSetter<i32>) {
1954    ///     // ✅ calling the signal sets the value
1955    ///     //    can be `setter(4)` on nightly
1956    ///     setter.set(4);
1957    /// }
1958    ///
1959    /// set_to_4(&set_count.into());
1960    /// assert_eq!(count.get(), 4);
1961    /// set_to_4(&set_double_input);
1962    /// assert_eq!(count.get(), 8);
1963    /// ```
1964    #[derive(Debug, PartialEq, Eq)]
1965    pub struct SignalSetter<T, S = SyncStorage>
1966    where
1967        T: 'static,
1968    {
1969        inner: SignalSetterTypes<T, S>,
1970        #[cfg(any(debug_assertions, leptos_debuginfo))]
1971        defined_at: &'static std::panic::Location<'static>,
1972    }
1973
1974    impl<T, S> Clone for SignalSetter<T, S> {
1975        fn clone(&self) -> Self {
1976            *self
1977        }
1978    }
1979
1980    impl<T: Default + 'static, S> Default for SignalSetter<T, S> {
1981        #[track_caller]
1982        fn default() -> Self {
1983            Self {
1984                inner: SignalSetterTypes::Default,
1985                #[cfg(any(debug_assertions, leptos_debuginfo))]
1986                defined_at: std::panic::Location::caller(),
1987            }
1988        }
1989    }
1990
1991    impl<T, S> Copy for SignalSetter<T, S> {}
1992
1993    impl<T, S> Set for SignalSetter<T, S>
1994    where
1995        T: 'static,
1996        S: Storage<ArcWriteSignal<T>> + Storage<Box<dyn Fn(T) + Send + Sync>>,
1997    {
1998        type Value = T;
1999
2000        fn set(&self, new_value: Self::Value) {
2001            match self.inner {
2002                SignalSetterTypes::Default => {}
2003                SignalSetterTypes::Write(w) => w.set(new_value),
2004                SignalSetterTypes::Mapped(s) => {
2005                    s.try_with_value(|setter| setter(new_value));
2006                }
2007            }
2008        }
2009
2010        fn try_set(&self, new_value: Self::Value) -> Option<Self::Value> {
2011            match self.inner {
2012                SignalSetterTypes::Default => Some(new_value),
2013                SignalSetterTypes::Write(w) => w.try_set(new_value),
2014                SignalSetterTypes::Mapped(s) => {
2015                    let mut new_value = Some(new_value);
2016
2017                    let _ = s.try_with_value(|setter| {
2018                        setter(new_value.take().unwrap())
2019                    });
2020
2021                    new_value
2022                }
2023            }
2024        }
2025    }
2026
2027    impl<T, S> SignalSetter<T, S>
2028    where
2029        S: Storage<Box<dyn Fn(T) + Send + Sync>>,
2030    {
2031        /// Wraps a signal-setting closure, i.e., any computation that sets one or more reactive signals.
2032        #[track_caller]
2033        pub fn map(mapped_setter: impl Fn(T) + Send + Sync + 'static) -> Self {
2034            Self {
2035                inner: SignalSetterTypes::Mapped(ArenaItem::new_with_storage(
2036                    Box::new(mapped_setter),
2037                )),
2038                #[cfg(any(debug_assertions, leptos_debuginfo))]
2039                defined_at: std::panic::Location::caller(),
2040            }
2041        }
2042    }
2043
2044    impl<T, S> From<WriteSignal<T, S>> for SignalSetter<T, S> {
2045        #[track_caller]
2046        fn from(value: WriteSignal<T, S>) -> Self {
2047            Self {
2048                inner: SignalSetterTypes::Write(value),
2049                #[cfg(any(debug_assertions, leptos_debuginfo))]
2050                defined_at: std::panic::Location::caller(),
2051            }
2052        }
2053    }
2054
2055    impl<T, S> From<RwSignal<T, S>> for SignalSetter<T, S>
2056    where
2057        T: Send + Sync + 'static,
2058        S: Storage<ArcRwSignal<T>> + Storage<ArcWriteSignal<T>>,
2059    {
2060        #[track_caller]
2061        fn from(value: RwSignal<T, S>) -> Self {
2062            Self {
2063                inner: SignalSetterTypes::Write(value.write_only()),
2064                #[cfg(any(debug_assertions, leptos_debuginfo))]
2065                defined_at: std::panic::Location::caller(),
2066            }
2067        }
2068    }
2069
2070    enum SignalSetterTypes<T, S = SyncStorage>
2071    where
2072        T: 'static,
2073    {
2074        Write(WriteSignal<T, S>),
2075        Mapped(ArenaItem<Box<dyn Fn(T) + Send + Sync>, S>),
2076        Default,
2077    }
2078
2079    impl<T, S> Clone for SignalSetterTypes<T, S> {
2080        fn clone(&self) -> Self {
2081            *self
2082        }
2083    }
2084
2085    impl<T, S> Copy for SignalSetterTypes<T, S> {}
2086
2087    impl<T, S> core::fmt::Debug for SignalSetterTypes<T, S>
2088    where
2089        T: core::fmt::Debug,
2090        S: core::fmt::Debug,
2091    {
2092        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2093            match self {
2094                Self::Write(arg0) => {
2095                    f.debug_tuple("WriteSignal").field(arg0).finish()
2096                }
2097                Self::Mapped(_) => f.debug_tuple("Mapped").finish(),
2098                Self::Default => {
2099                    f.debug_tuple("SignalSetter<Default>").finish()
2100                }
2101            }
2102        }
2103    }
2104
2105    impl<T, S> PartialEq for SignalSetterTypes<T, S>
2106    where
2107        T: PartialEq,
2108    {
2109        fn eq(&self, other: &Self) -> bool {
2110            match (self, other) {
2111                (Self::Write(l0), Self::Write(r0)) => l0 == r0,
2112                (Self::Mapped(l0), Self::Mapped(r0)) => std::ptr::eq(l0, r0),
2113                _ => false,
2114            }
2115        }
2116    }
2117
2118    impl<T, S> Eq for SignalSetterTypes<T, S> where T: PartialEq {}
2119}