mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
MaybeSignal and MaybeProp
This commit is contained in:
parent
986fbe5328
commit
9818e7cb68
3 changed files with 322 additions and 31 deletions
|
@ -3,6 +3,7 @@ use crate::{
|
|||
owner::{StoredData, StoredValue},
|
||||
signal::guards::{Mapped, Plain, ReadGuard},
|
||||
traits::{DefinedAt, ReadUntracked, Track},
|
||||
unwrap_signal,
|
||||
};
|
||||
use std::{fmt::Debug, hash::Hash, panic::Location};
|
||||
|
||||
|
@ -112,3 +113,10 @@ impl<T: Send + Sync + 'static> ReadUntracked for Memo<T> {
|
|||
self.get_value().map(|inner| inner.read_untracked())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> From<Memo<T>> for ArcMemo<T> {
|
||||
#[track_caller]
|
||||
fn from(value: Memo<T>) -> Self {
|
||||
value.get_value().unwrap_or_else(unwrap_signal!(value))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
|||
computed::{ArcMemo, Memo},
|
||||
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
|
||||
traits::With,
|
||||
wrappers::read::{MaybeSignal, Signal},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -59,9 +60,7 @@ impl<T: Send + Sync + Serialize + 'static> Serialize for ArcMemo<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO MaybeSignal
|
||||
impl<T: Serialize> Serialize for MaybeSignal<T> {
|
||||
impl<T: Send + Sync + Serialize> Serialize for MaybeSignal<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
|
@ -70,7 +69,6 @@ impl<T: Serialize> Serialize for MaybeSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO MaybeProp
|
||||
impl<T: Serialize> Serialize for MaybeProp<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
@ -90,15 +88,14 @@ impl<T: Serialize> Serialize for MaybeProp<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO Signal
|
||||
impl<T: Clone + Serialize> Serialize for Signal<T> {
|
||||
impl<T: Send + Sync + Clone + Serialize> Serialize for Signal<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.get().serialize(serializer)
|
||||
self.with(|value| value.serialize(serializer))
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/* Deserialization for signal types */
|
||||
|
||||
|
@ -120,4 +117,11 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for ArcRwSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO MaybeSignal
|
||||
impl<'de, T: Deserialize<'de>> Deserialize<'de> for MaybeSignal<T> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(MaybeSignal::Static)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
pub mod read {
|
||||
use crate::{
|
||||
computed::ArcMemo,
|
||||
computed::{ArcMemo, Memo},
|
||||
owner::StoredValue,
|
||||
signal::ArcReadSignal,
|
||||
signal::{ArcReadSignal, ReadSignal, RwSignal},
|
||||
traits::{DefinedAt, Get, GetUntracked, With, WithUntracked},
|
||||
untrack,
|
||||
};
|
||||
|
@ -179,41 +179,43 @@ pub mod read {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> GetUntracked for Signal<T>
|
||||
impl<T> WithUntracked for Signal<T>
|
||||
where
|
||||
T: Send + Sync + Clone,
|
||||
T: Send + Sync,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn try_get_untracked(&self) -> Option<Self::Value> {
|
||||
fn try_with_untracked<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(&Self::Value) -> U,
|
||||
) -> Option<U> {
|
||||
self.inner
|
||||
// cloning here clones the inner Arc and releases the lock, in case anything inside needs to take it
|
||||
// this happens particularly in derived signals, because they need to to access the
|
||||
// global arena again
|
||||
//
|
||||
// note that .read() multiple times in the same thread on a std RwLock can deadlock
|
||||
// to avoid writer starvation, which is why this happens
|
||||
.with_value(|inner| inner.clone())
|
||||
.and_then(|inner| match &inner {
|
||||
SignalTypes::ReadSignal(i) => i.try_get_untracked(),
|
||||
SignalTypes::Memo(i) => i.try_get_untracked(),
|
||||
SignalTypes::DerivedSignal(i) => Some(untrack(|| i())),
|
||||
.with_value(|inner| match &inner {
|
||||
SignalTypes::ReadSignal(i) => i.try_with_untracked(fun),
|
||||
SignalTypes::Memo(i) => i.try_with_untracked(fun),
|
||||
SignalTypes::DerivedSignal(i) => {
|
||||
Some(untrack(|| fun(&i())))
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Get for Signal<T>
|
||||
impl<T> With for Signal<T>
|
||||
where
|
||||
T: Send + Sync + Clone,
|
||||
T: Send + Sync,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn try_get(&self) -> Option<Self::Value> {
|
||||
fn try_with<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(&Self::Value) -> U,
|
||||
) -> Option<U> {
|
||||
self.inner
|
||||
.with_value(|inner| match &inner {
|
||||
SignalTypes::ReadSignal(i) => i.try_get(),
|
||||
SignalTypes::Memo(i) => i.try_get(),
|
||||
SignalTypes::DerivedSignal(i) => Some(i()),
|
||||
SignalTypes::ReadSignal(i) => i.try_with(fun),
|
||||
SignalTypes::Memo(i) => i.try_with(fun),
|
||||
SignalTypes::DerivedSignal(i) => Some(fun(&i())),
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
@ -271,4 +273,281 @@ pub mod read {
|
|||
Self::derive(|| Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<ReadSignal<T>> for Signal<T> {
|
||||
#[track_caller]
|
||||
fn from(value: ReadSignal<T>) -> Self {
|
||||
Self {
|
||||
inner: StoredValue::new(SignalTypes::ReadSignal(value.into())),
|
||||
#[cfg(any(debug_assertions, feature = "ssr"))]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<RwSignal<T>> for Signal<T> {
|
||||
#[track_caller]
|
||||
fn from(value: RwSignal<T>) -> Self {
|
||||
Self {
|
||||
inner: StoredValue::new(SignalTypes::ReadSignal(
|
||||
value.read_only().into(),
|
||||
)),
|
||||
#[cfg(any(debug_assertions, feature = "ssr"))]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<Memo<T>> for Signal<T> {
|
||||
#[track_caller]
|
||||
fn from(value: Memo<T>) -> Self {
|
||||
Self {
|
||||
inner: StoredValue::new(SignalTypes::Memo(value.into())),
|
||||
#[cfg(any(debug_assertions, feature = "ssr"))]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum MaybeSignal<T>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
/// An unchanging value of type `T`.
|
||||
Static(T),
|
||||
/// A reactive signal that contains a value of type `T`.
|
||||
Dynamic(Signal<T>),
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for MaybeSignal<T> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Static(item) => Self::Static(item.clone()),
|
||||
Self::Dynamic(signal) => Self::Dynamic(*signal),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> Copy for MaybeSignal<T> {}
|
||||
|
||||
impl<T: Default> Default for MaybeSignal<T> {
|
||||
fn default() -> Self {
|
||||
Self::Static(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DefinedAt for MaybeSignal<T> {
|
||||
fn defined_at(&self) -> Option<&'static Location<'static>> {
|
||||
// TODO this could be improved, but would require moving from an enum to a struct here.
|
||||
// Probably not worth it for relatively small benefits.
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> WithUntracked for MaybeSignal<T> {
|
||||
type Value = T;
|
||||
|
||||
fn try_with_untracked<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(&Self::Value) -> U,
|
||||
) -> Option<U> {
|
||||
match self {
|
||||
Self::Static(t) => Some(fun(t)),
|
||||
Self::Dynamic(s) => s.try_with_untracked(fun),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> With for MaybeSignal<T> {
|
||||
type Value = T;
|
||||
|
||||
fn try_with<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(&Self::Value) -> U,
|
||||
) -> Option<U> {
|
||||
match self {
|
||||
Self::Static(t) => Some(fun(t)),
|
||||
Self::Dynamic(s) => s.try_with(fun),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MaybeSignal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
pub fn derive(
|
||||
derived_signal: impl Fn() -> T + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
Self::Dynamic(Signal::derive(derived_signal))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for MaybeSignal<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Self::Static(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<ReadSignal<T>> for MaybeSignal<T> {
|
||||
fn from(value: ReadSignal<T>) -> Self {
|
||||
Self::Dynamic(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<RwSignal<T>> for MaybeSignal<T> {
|
||||
fn from(value: RwSignal<T>) -> Self {
|
||||
Self::Dynamic(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<Memo<T>> for MaybeSignal<T> {
|
||||
fn from(value: Memo<T>) -> Self {
|
||||
Self::Dynamic(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Signal<T>> for MaybeSignal<T> {
|
||||
fn from(value: Signal<T>) -> Self {
|
||||
Self::Dynamic(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for MaybeSignal<String> {
|
||||
fn from(value: &str) -> Self {
|
||||
Self::Static(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct MaybeProp<T: Send + Sync + 'static>(
|
||||
pub(crate) Option<MaybeSignal<Option<T>>>,
|
||||
);
|
||||
|
||||
impl<T: Send + Sync + Copy> Copy for MaybeProp<T> {}
|
||||
|
||||
impl<T: Send + Sync> Default for MaybeProp<T> {
|
||||
fn default() -> Self {
|
||||
Self(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> DefinedAt for MaybeProp<T> {
|
||||
fn defined_at(&self) -> Option<&'static Location<'static>> {
|
||||
// TODO this can be improved by adding a defined_at field
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> WithUntracked for MaybeProp<T> {
|
||||
type Value = Option<T>;
|
||||
|
||||
fn try_with_untracked<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(&Self::Value) -> U,
|
||||
) -> Option<U> {
|
||||
self.0.as_ref().and_then(|n| n.try_with_untracked(fun))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> With for MaybeProp<T> {
|
||||
type Value = Option<T>;
|
||||
|
||||
fn try_with<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(&Self::Value) -> U,
|
||||
) -> Option<U> {
|
||||
self.0.as_ref().and_then(|n| n.try_with(fun))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MaybeProp<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
pub fn derive(
|
||||
derived_signal: impl Fn() -> Option<T> + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
Self(Some(MaybeSignal::derive(derived_signal)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<T> for MaybeProp<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Self(Some(MaybeSignal::from(Some(value))))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<Option<T>> for MaybeProp<T> {
|
||||
fn from(value: Option<T>) -> Self {
|
||||
Self(Some(MaybeSignal::from(value)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<MaybeSignal<Option<T>>> for MaybeProp<T> {
|
||||
fn from(value: MaybeSignal<Option<T>>) -> Self {
|
||||
Self(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<Option<MaybeSignal<Option<T>>>> for MaybeProp<T> {
|
||||
fn from(value: Option<MaybeSignal<Option<T>>>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<ReadSignal<Option<T>>> for MaybeProp<T> {
|
||||
fn from(value: ReadSignal<Option<T>>) -> Self {
|
||||
Self(Some(value.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<RwSignal<Option<T>>> for MaybeProp<T> {
|
||||
fn from(value: RwSignal<Option<T>>) -> Self {
|
||||
Self(Some(value.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<Memo<Option<T>>> for MaybeProp<T> {
|
||||
fn from(value: Memo<Option<T>>) -> Self {
|
||||
Self(Some(value.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> From<Signal<Option<T>>> for MaybeProp<T> {
|
||||
fn from(value: Signal<Option<T>>) -> Self {
|
||||
Self(Some(value.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + Clone> From<ReadSignal<T>> for MaybeProp<T> {
|
||||
fn from(value: ReadSignal<T>) -> Self {
|
||||
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + Clone> From<RwSignal<T>> for MaybeProp<T> {
|
||||
fn from(value: RwSignal<T>) -> Self {
|
||||
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + Clone> From<Memo<T>> for MaybeProp<T> {
|
||||
fn from(value: Memo<T>) -> Self {
|
||||
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + Clone> From<Signal<T>> for MaybeProp<T> {
|
||||
fn from(value: Signal<T>) -> Self {
|
||||
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for MaybeProp<String> {
|
||||
fn from(value: &str) -> Self {
|
||||
Self(Some(MaybeSignal::from(Some(value.to_string()))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue