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