smooth out StoredValue APIs

This commit is contained in:
Greg Johnston 2024-05-08 20:14:38 -04:00
parent 9818e7cb68
commit d8d2fdac5d
14 changed files with 280 additions and 372 deletions

View File

@ -2,7 +2,7 @@ use crate::{
diagnostics::is_suppressing_resource_load,
owner::{Owner, StoredValue},
signal::{ArcRwSignal, RwSignal},
traits::{DefinedAt, GetUntracked, Update},
traits::{DefinedAt, Dispose, GetUntracked, Update},
unwrap_signal,
};
use any_spawner::Executor;
@ -161,6 +161,12 @@ where
defined_at: &'static Location<'static>,
}
impl<I: 'static, O: 'static> Dispose for Action<I, O> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<I, O> Action<I, O>
where
I: Send + Sync + 'static,
@ -183,7 +189,7 @@ where
pub fn version(&self) -> RwSignal<usize> {
let inner = self
.inner
.with_value(|inner| inner.version())
.try_with_value(|inner| inner.version())
.unwrap_or_else(unwrap_signal!(self));
inner.into()
}
@ -192,7 +198,7 @@ where
pub fn input(&self) -> RwSignal<Option<I>> {
let inner = self
.inner
.with_value(|inner| inner.input())
.try_with_value(|inner| inner.input())
.unwrap_or_else(unwrap_signal!(self));
inner.into()
}
@ -201,7 +207,7 @@ where
pub fn value(&self) -> RwSignal<Option<O>> {
let inner = self
.inner
.with_value(|inner| inner.value())
.try_with_value(|inner| inner.value())
.unwrap_or_else(unwrap_signal!(self));
inner.into()
}

View File

@ -2,7 +2,7 @@ use crate::{
diagnostics::is_suppressing_resource_load,
owner::StoredValue,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
traits::{DefinedAt, GetUntracked, Set, Update},
traits::{DefinedAt, Dispose, GetUntracked, Set, Update},
unwrap_signal,
};
use any_spawner::Executor;
@ -18,6 +18,12 @@ where
defined_at: &'static Location<'static>,
}
impl<I: 'static, O: 'static> Dispose for MultiAction<I, O> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<I, O> DefinedAt for MultiAction<I, O>
where
I: 'static,
@ -89,7 +95,7 @@ where
/// The set of all submissions to this multi-action.
pub fn submissions(&self) -> ReadSignal<Vec<ArcSubmission<I, O>>> {
self.inner
.with_value(|inner| inner.submissions())
.try_with_value(|inner| inner.submissions())
.unwrap_or_else(unwrap_signal!(self))
.into()
}
@ -97,7 +103,7 @@ where
/// How many times an action has successfully resolved.
pub fn version(&self) -> RwSignal<usize> {
self.inner
.with_value(|inner| inner.version())
.try_with_value(|inner| inner.version())
.unwrap_or_else(unwrap_signal!(self))
.into()
}

View File

@ -6,9 +6,9 @@ use crate::{
AnySource, AnySubscriber, ReactiveNode, Source, Subscriber,
ToAnySource, ToAnySubscriber,
},
owner::{StoredData, StoredValue},
owner::StoredValue,
signal::guards::{Mapped, Plain, ReadGuard},
traits::{DefinedAt, ReadUntracked},
traits::{DefinedAt, Dispose, ReadUntracked},
unwrap_signal,
};
use core::fmt::Debug;
@ -23,6 +23,12 @@ pub struct AsyncDerived<T: Send + Sync + 'static> {
inner: StoredValue<ArcAsyncDerived<T>>,
}
impl<T: Send + Sync + 'static> Dispose for AsyncDerived<T> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<T: Send + Sync + 'static> From<ArcAsyncDerived<T>> for AsyncDerived<T> {
fn from(value: ArcAsyncDerived<T>) -> Self {
#[cfg(debug_assertions)]
@ -35,18 +41,6 @@ impl<T: Send + Sync + 'static> From<ArcAsyncDerived<T>> for AsyncDerived<T> {
}
}
impl<T: Send + Sync + 'static> StoredData for AsyncDerived<T> {
type Data = ArcAsyncDerived<T>;
fn get_value(&self) -> Option<Self::Data> {
self.inner.get()
}
fn dispose(&self) {
self.inner.dispose();
}
}
impl<T: Send + Sync + 'static> AsyncDerived<T> {
#[track_caller]
pub fn new<Fut>(fun: impl Fn() -> Fut + Send + Sync + 'static) -> Self
@ -165,13 +159,14 @@ impl<T: Send + Sync + 'static> ReadUntracked for AsyncDerived<T> {
type Value = ReadGuard<AsyncState<T>, Plain<AsyncState<T>>>;
fn try_read_untracked(&self) -> Option<Self::Value> {
self.get_value().map(|inner| inner.read_untracked())
self.inner.get().map(|inner| inner.read_untracked())
}
}
impl<T: Send + Sync + 'static> ToAnySource for AsyncDerived<T> {
fn to_any_source(&self) -> AnySource {
self.get_value()
self.inner
.get()
.map(|inner| inner.to_any_source())
.unwrap_or_else(unwrap_signal!(self))
}
@ -179,7 +174,8 @@ impl<T: Send + Sync + 'static> ToAnySource for AsyncDerived<T> {
impl<T: Send + Sync + 'static> ToAnySubscriber for AsyncDerived<T> {
fn to_any_subscriber(&self) -> AnySubscriber {
self.get_value()
self.inner
.get()
.map(|inner| inner.to_any_subscriber())
.unwrap_or_else(unwrap_signal!(self))
}
@ -187,19 +183,19 @@ impl<T: Send + Sync + 'static> ToAnySubscriber for AsyncDerived<T> {
impl<T: Send + Sync + 'static> Source for AsyncDerived<T> {
fn add_subscriber(&self, subscriber: AnySubscriber) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.add_subscriber(subscriber);
}
}
fn remove_subscriber(&self, subscriber: &AnySubscriber) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.remove_subscriber(subscriber);
}
}
fn clear_subscribers(&self) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.clear_subscribers();
}
}
@ -207,25 +203,25 @@ impl<T: Send + Sync + 'static> Source for AsyncDerived<T> {
impl<T: Send + Sync + 'static> ReactiveNode for AsyncDerived<T> {
fn mark_dirty(&self) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.mark_dirty();
}
}
fn mark_check(&self) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.mark_check();
}
}
fn mark_subscribers_check(&self) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.mark_subscribers_check();
}
}
fn update_if_necessary(&self) -> bool {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.update_if_necessary()
} else {
false
@ -235,13 +231,13 @@ impl<T: Send + Sync + 'static> ReactiveNode for AsyncDerived<T> {
impl<T: Send + Sync + 'static> Subscriber for AsyncDerived<T> {
fn add_source(&self, source: AnySource) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.add_source(source);
}
}
fn clear_sources(&self, subscriber: &AnySubscriber) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.clear_sources(subscriber);
}
}

View File

@ -1,8 +1,8 @@
use super::{inner::MemoInner, ArcMemo};
use crate::{
owner::{StoredData, StoredValue},
owner::StoredValue,
signal::guards::{Mapped, Plain, ReadGuard},
traits::{DefinedAt, ReadUntracked, Track},
traits::{DefinedAt, Dispose, ReadUntracked, Track},
unwrap_signal,
};
use std::{fmt::Debug, hash::Hash, panic::Location};
@ -13,6 +13,12 @@ pub struct Memo<T: Send + Sync + 'static> {
inner: StoredValue<ArcMemo<T>>,
}
impl<T: Send + Sync + 'static> Dispose for Memo<T> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<T: Send + Sync + 'static> From<ArcMemo<T>> for Memo<T> {
#[track_caller]
fn from(value: ArcMemo<T>) -> Self {
@ -73,18 +79,6 @@ impl<T: Send + Sync + 'static> Hash for Memo<T> {
}
}
impl<T: Send + Sync + 'static> StoredData for Memo<T> {
type Data = ArcMemo<T>;
fn get_value(&self) -> Option<Self::Data> {
self.inner.get()
}
fn dispose(&self) {
self.inner.dispose();
}
}
impl<T: Send + Sync + 'static> DefinedAt for Memo<T> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(debug_assertions)]
@ -100,7 +94,7 @@ impl<T: Send + Sync + 'static> DefinedAt for Memo<T> {
impl<T: Send + Sync + 'static> Track for Memo<T> {
fn track(&self) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.track();
}
}
@ -110,13 +104,13 @@ impl<T: Send + Sync + 'static> ReadUntracked for Memo<T> {
type Value = ReadGuard<T, Mapped<Plain<MemoInner<T>>, T>>;
fn try_read_untracked(&self) -> Option<Self::Value> {
self.get_value().map(|inner| inner.read_untracked())
self.inner.get().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))
value.inner.get().unwrap_or_else(unwrap_signal!(value))
}
}

View File

@ -3,6 +3,7 @@ use crate::{
effect::inner::EffectInner,
graph::{AnySubscriber, SourceSet, Subscriber, ToAnySubscriber},
owner::{Owner, StoredValue},
traits::Dispose,
};
use any_spawner::Executor;
use futures::StreamExt;
@ -16,6 +17,12 @@ pub struct Effect {
inner: StoredValue<Option<Arc<RwLock<EffectInner>>>>,
}
impl Dispose for Effect {
fn dispose(self) {
self.inner.dispose()
}
}
fn effect_base() -> (Receiver, Owner, Arc<RwLock<EffectInner>>) {
let (mut observer, rx) = channel();
@ -103,7 +110,7 @@ impl Effect {
impl ToAnySubscriber for Effect {
fn to_any_subscriber(&self) -> AnySubscriber {
self.inner
.with_value(|inner| {
.try_with_value(|inner| {
inner.as_ref().map(|inner| inner.to_any_subscriber())
})
.flatten()

View File

@ -96,5 +96,5 @@ pub type PinnedLocalFuture<T> = Pin<Box<dyn Future<Output = T>>>;
pub type PinnedStream<T> = Pin<Box<dyn Stream<Item = T> + Send + Sync>>;
pub mod prelude {
pub use crate::{owner::StoredData, traits::*};
pub use crate::traits::*;
}

View File

@ -12,12 +12,13 @@ use std::{
mod arena;
mod context;
mod stored_value;
use self::arena::Arena;
#[cfg(feature = "sandboxed-arenas")]
pub use arena::sandboxed::Sandboxed;
use arena::NodeId;
pub use arena::{StoredData, StoredValue};
pub use context::*;
pub use stored_value::StoredValue;
#[derive(Debug, Clone, Default)]
#[must_use]

View File

@ -168,266 +168,3 @@ pub mod sandboxed {
}
}
}
#[derive(Debug)]
pub struct StoredValue<T> {
node: NodeId,
ty: PhantomData<T>,
}
impl<T> Copy for StoredValue<T> {}
impl<T> Clone for StoredValue<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> PartialEq for StoredValue<T> {
fn eq(&self, other: &Self) -> bool {
self.node == other.node && self.ty == other.ty
}
}
impl<T> Eq for StoredValue<T> {}
impl<T> Hash for StoredValue<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.node.hash(state);
self.ty.hash(state);
}
}
impl<T> StoredValue<T>
where
T: Send + Sync + 'static,
{
#[track_caller]
pub fn new(value: T) -> Self {
let node = {
Arena::with_mut(|arena| {
arena.insert(Box::new(value) as Box<dyn Any + Send + Sync>)
})
};
OWNER.with(|o| {
if let Some(owner) = &*o.borrow() {
owner.register(node);
}
});
Self {
node,
ty: PhantomData,
}
}
pub fn with_value<U>(&self, fun: impl FnOnce(&T) -> U) -> Option<U> {
Arena::with(|arena| {
let m = arena.get(self.node);
m.and_then(|n| n.downcast_ref::<T>()).map(fun)
})
}
pub fn update_value<U>(&self, fun: impl FnOnce(&mut T) -> U) -> Option<U> {
Arena::with_mut(|arena| {
let m = arena.get_mut(self.node);
m.and_then(|n| n.downcast_mut::<T>()).map(fun)
})
}
pub fn get(&self) -> Option<T>
where
T: Clone,
{
self.with_value(T::clone)
}
pub fn set_value(&self, value: T) {
self.update_value(|n| *n = value);
}
pub fn exists(&self) -> bool
where
T: Clone,
{
Arena::with(|arena| arena.contains_key(self.node))
}
pub fn dispose(&self) {
Arena::with_mut(|arena| arena.remove(self.node));
}
}
#[inline(always)]
#[track_caller]
#[deprecated = "This function is being removed to conform to Rust \
idioms.Please use `StoredValue::new()` instead."]
pub fn store_value<T>(value: T) -> StoredValue<T>
where
T: Send + Sync + 'static,
{
StoredValue::new(value)
}
#[doc(hidden)]
pub trait StoredData {
type Data;
fn get_value(&self) -> Option<Self::Data>;
fn dispose(&self);
}
/*impl<T> ReactiveNode for T
where
T: StoredData,
T::Data: ReactiveNode,
{
fn mark_dirty(&self) {
if let Some(inner) = self.get_value() {
inner.mark_dirty();
}
}
fn mark_check(&self) {
if let Some(inner) = self.get_value() {
inner.mark_check();
}
}
fn mark_subscribers_check(&self) {
if let Some(inner) = self.get_value() {
inner.mark_subscribers_check();
}
}
fn update_if_necessary(&self) -> bool {
if let Some(inner) = self.get_value() {
inner.update_if_necessary()
} else {
false
}
}
}
impl<T> Source for T
where
T: StoredData,
T::Data: Source,
{
fn add_subscriber(&self, subscriber: AnySubscriber) {
if let Some(inner) = self.get_value() {
inner.add_subscriber(subscriber);
}
}
fn remove_subscriber(&self, subscriber: &AnySubscriber) {
if let Some(inner) = self.get_value() {
inner.remove_subscriber(subscriber);
}
}
fn clear_subscribers(&self) {
if let Some(inner) = self.get_value() {
inner.clear_subscribers();
}
}
}
impl<T> Subscriber for T
where
T: StoredData,
T::Data: Subscriber,
{
fn add_source(&self, source: AnySource) {
if let Some(inner) = self.get_value() {
inner.add_source(source);
}
}
fn clear_sources(&self, subscriber: &AnySubscriber) {
if let Some(inner) = self.get_value() {
inner.clear_sources(subscriber);
}
}
}
impl<T> DefinedAt for T
where
T: StoredData,
T::Data: DefinedAt,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
self.get_value().and_then(|n| n.defined_at())
}
}
impl<T> ToAnySource for T
where
T: StoredData,
T::Data: ToAnySource + DefinedAt,
{
#[track_caller]
fn to_any_source(&self) -> AnySource {
self.get_value()
.map(|inner| inner.to_any_source())
.unwrap_or_else(unwrap_signal!(self))
}
}
impl<T> ToAnySubscriber for T
where
T: StoredData,
T::Data: ToAnySubscriber + DefinedAt,
{
#[track_caller]
fn to_any_subscriber(&self) -> AnySubscriber {
self.get_value()
.map(|inner| inner.to_any_subscriber())
.unwrap_or_else(unwrap_signal!(self))
}
}
impl<T> WithUntracked for T
where
T: StoredData + DefinedAt,
T::Data: WithUntracked,
{
type Value = <<T as StoredData>::Data as WithUntracked>::Value;
#[track_caller]
fn try_with_untracked<U>(
&self,
fun: impl FnOnce(&Self::Value) -> U,
) -> Option<U> {
self.get_value().and_then(|n| n.try_with_untracked(fun))
}
}
impl<T> Trigger for T
where
T: StoredData,
T::Data: Trigger,
{
fn trigger(&self) {
if let Some(inner) = self.get_value() {
inner.trigger();
}
}
}
impl<T> UpdateUntracked for T
where
T: StoredData,
T::Data: UpdateUntracked,
{
type Value = <<T as StoredData>::Data as UpdateUntracked>::Value;
fn try_update_untracked<U>(
&self,
fun: impl FnOnce(&mut Self::Value) -> U,
) -> Option<U> {
self.get_value()
.and_then(|inner| inner.try_update_untracked(fun))
}
}*/

View File

@ -0,0 +1,163 @@
use super::{
arena::{Arena, NodeId},
OWNER,
};
use crate::{
traits::{DefinedAt, Dispose},
unwrap_signal,
};
use std::{any::Any, hash::Hash, marker::PhantomData, panic::Location};
#[derive(Debug)]
pub struct StoredValue<T> {
node: NodeId,
ty: PhantomData<T>,
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
impl<T> Copy for StoredValue<T> {}
impl<T> Clone for StoredValue<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> PartialEq for StoredValue<T> {
fn eq(&self, other: &Self) -> bool {
self.node == other.node && self.ty == other.ty
}
}
impl<T> Eq for StoredValue<T> {}
impl<T> Hash for StoredValue<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.node.hash(state);
self.ty.hash(state);
}
}
impl<T> DefinedAt for StoredValue<T> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(debug_assertions))]
{
None
}
}
}
impl<T> StoredValue<T>
where
T: Send + Sync + 'static,
{
#[track_caller]
pub fn new(value: T) -> Self {
let node = {
Arena::with_mut(|arena| {
arena.insert(Box::new(value) as Box<dyn Any + Send + Sync>)
})
};
OWNER.with(|o| {
if let Some(owner) = &*o.borrow() {
owner.register(node);
}
});
Self {
node,
ty: PhantomData,
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
pub fn try_with_value<U>(&self, fun: impl FnOnce(&T) -> U) -> Option<U> {
Arena::with(|arena| {
let m = arena.get(self.node);
m.and_then(|n| n.downcast_ref::<T>()).map(fun)
})
}
pub fn with_value<U>(&self, fun: impl FnOnce(&T) -> U) -> U {
self.try_with_value(fun)
.unwrap_or_else(unwrap_signal!(self))
}
pub fn try_update_value<U>(
&self,
fun: impl FnOnce(&mut T) -> U,
) -> Option<U> {
Arena::with_mut(|arena| {
let m = arena.get_mut(self.node);
m.and_then(|n| n.downcast_mut::<T>()).map(fun)
})
}
pub fn update_value<U>(&self, fun: impl FnOnce(&mut T) -> U) {
self.try_update_value(fun);
}
pub fn try_set_value(&self, value: T) -> Option<T> {
Arena::with_mut(|arena| {
let m = arena.get_mut(self.node);
match m.and_then(|n| n.downcast_mut::<T>()) {
Some(inner) => {
*inner = value;
None
}
None => Some(value),
}
})
}
pub fn set_value(&self, value: T) {
self.update_value(|n| *n = value);
}
pub fn exists(&self) -> bool
where
T: Clone,
{
Arena::with(|arena| arena.contains_key(self.node))
}
}
impl<T> StoredValue<T>
where
T: Send + Sync + Clone + 'static,
{
pub fn try_get_value(&self) -> Option<T> {
self.try_with_value(T::clone)
}
pub fn get_value(&self) -> T {
self.with_value(T::clone)
}
pub(crate) fn get(&self) -> Option<T> {
self.try_get_value()
}
}
impl<T> Dispose for StoredValue<T> {
fn dispose(self) {
Arena::with_mut(|arena| arena.remove(self.node));
}
}
#[inline(always)]
#[track_caller]
#[deprecated = "This function is being removed to conform to Rust \
idioms.Please use `StoredValue::new()` instead."]
pub fn store_value<T>(value: T) -> StoredValue<T>
where
T: Send + Sync + 'static,
{
StoredValue::new(value)
}

View File

@ -5,8 +5,8 @@ use super::{
};
use crate::{
graph::SubscriberSet,
owner::{StoredData, StoredValue},
traits::{DefinedAt, IsDisposed, ReadUntracked},
owner::StoredValue,
traits::{DefinedAt, Dispose, IsDisposed, ReadUntracked},
unwrap_signal,
};
use core::fmt::Debug;
@ -22,6 +22,12 @@ pub struct ReadSignal<T: Send + Sync + 'static> {
pub(crate) inner: StoredValue<ArcReadSignal<T>>,
}
impl<T: Send + Sync + 'static> Dispose for ReadSignal<T> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<T: Send + Sync + 'static> Copy for ReadSignal<T> {}
impl<T: Send + Sync + 'static> Clone for ReadSignal<T> {
@ -72,24 +78,12 @@ impl<T: Send + Sync + 'static> IsDisposed for ReadSignal<T> {
}
}
impl<T: Send + Sync + 'static> StoredData for ReadSignal<T> {
type Data = ArcReadSignal<T>;
fn get_value(&self) -> Option<Self::Data> {
self.inner.get()
}
fn dispose(&self) {
self.inner.dispose();
}
}
impl<T: Send + Sync + 'static> AsSubscriberSet for ReadSignal<T> {
type Output = Arc<RwLock<SubscriberSet>>;
fn as_subscriber_set(&self) -> Option<Self::Output> {
self.inner
.with_value(|inner| inner.as_subscriber_set())
.try_with_value(|inner| inner.as_subscriber_set())
.flatten()
}
}
@ -98,7 +92,9 @@ impl<T: Send + Sync + 'static> ReadUntracked for ReadSignal<T> {
type Value = ReadGuard<T, Plain<T>>;
fn try_read_untracked(&self) -> Option<Self::Value> {
self.get_value().map(|inner| inner.read_untracked())
self.inner
.try_get_value()
.map(|inner| inner.read_untracked())
}
}
@ -116,6 +112,6 @@ impl<T: Send + Sync + 'static> From<ArcReadSignal<T>> for ReadSignal<T> {
impl<T: Send + Sync + 'static> From<ReadSignal<T>> for ArcReadSignal<T> {
#[track_caller]
fn from(value: ReadSignal<T>) -> Self {
value.get_value().unwrap_or_else(unwrap_signal!(value))
value.inner.get().unwrap_or_else(unwrap_signal!(value))
}
}

View File

@ -5,8 +5,10 @@ use super::{
};
use crate::{
graph::{ReactiveNode, SubscriberSet},
owner::{StoredData, StoredValue},
traits::{DefinedAt, IsDisposed, ReadUntracked, Trigger, UpdateUntracked},
owner::StoredValue,
traits::{
DefinedAt, Dispose, IsDisposed, ReadUntracked, Trigger, UpdateUntracked,
},
unwrap_signal,
};
use core::fmt::Debug;
@ -22,6 +24,12 @@ pub struct RwSignal<T: 'static> {
inner: StoredValue<ArcRwSignal<T>>,
}
impl<T: Send + Sync + 'static> Dispose for RwSignal<T> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<T: Send + Sync + 'static> RwSignal<T> {
#[cfg_attr(
feature = "tracing",
@ -41,7 +49,8 @@ impl<T: Send + Sync + 'static> RwSignal<T> {
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: StoredValue::new(
self.get_value()
self.inner
.get()
.map(|inner| inner.read_only())
.unwrap_or_else(unwrap_signal!(self)),
),
@ -54,7 +63,8 @@ impl<T: Send + Sync + 'static> RwSignal<T> {
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: StoredValue::new(
self.get_value()
self.inner
.get()
.map(|inner| inner.write_only())
.unwrap_or_else(unwrap_signal!(self)),
),
@ -140,24 +150,12 @@ impl<T: Send + Sync + 'static> IsDisposed for RwSignal<T> {
}
}
impl<T: Send + Sync + 'static> StoredData for RwSignal<T> {
type Data = ArcRwSignal<T>;
fn get_value(&self) -> Option<Self::Data> {
self.inner.get()
}
fn dispose(&self) {
self.inner.dispose();
}
}
impl<T: Send + Sync + 'static> AsSubscriberSet for RwSignal<T> {
type Output = Arc<RwLock<SubscriberSet>>;
fn as_subscriber_set(&self) -> Option<Self::Output> {
self.inner
.with_value(|inner| inner.as_subscriber_set())
.try_with_value(|inner| inner.as_subscriber_set())
.flatten()
}
}
@ -166,7 +164,7 @@ impl<T: Send + Sync + 'static> ReadUntracked for RwSignal<T> {
type Value = ReadGuard<T, Plain<T>>;
fn try_read_untracked(&self) -> Option<Self::Value> {
self.get_value().map(|inner| inner.read_untracked())
self.inner.get().map(|inner| inner.read_untracked())
}
}
@ -183,7 +181,7 @@ impl<T: Send + Sync + 'static> UpdateUntracked for RwSignal<T> {
&self,
fun: impl FnOnce(&mut Self::Value) -> U,
) -> Option<U> {
self.get_value().and_then(|n| n.try_update_untracked(fun))
self.inner.get().and_then(|n| n.try_update_untracked(fun))
}
}
@ -208,6 +206,6 @@ impl<'a, T: Send + Sync + 'static> From<&'a ArcRwSignal<T>> for RwSignal<T> {
impl<T: Send + Sync + 'static> From<RwSignal<T>> for ArcRwSignal<T> {
#[track_caller]
fn from(value: RwSignal<T>) -> Self {
value.get_value().unwrap_or_else(unwrap_signal!(value))
value.inner.get().unwrap_or_else(unwrap_signal!(value))
}
}

View File

@ -1,7 +1,7 @@
use super::ArcWriteSignal;
use crate::{
owner::{StoredData, StoredValue},
traits::{DefinedAt, IsDisposed, Trigger, UpdateUntracked},
owner::StoredValue,
traits::{DefinedAt, Dispose, IsDisposed, Trigger, UpdateUntracked},
};
use core::fmt::Debug;
use std::{hash::Hash, panic::Location};
@ -12,6 +12,12 @@ pub struct WriteSignal<T: Send + Sync + 'static> {
pub(crate) inner: StoredValue<ArcWriteSignal<T>>,
}
impl<T: Send + Sync + 'static> Dispose for WriteSignal<T> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<T: Send + Sync + 'static> Copy for WriteSignal<T> {}
impl<T: Send + Sync + 'static> Clone for WriteSignal<T> {
@ -62,21 +68,9 @@ impl<T: Send + Sync + 'static> IsDisposed for WriteSignal<T> {
}
}
impl<T: Send + Sync + 'static> StoredData for WriteSignal<T> {
type Data = ArcWriteSignal<T>;
fn get_value(&self) -> Option<Self::Data> {
self.inner.get()
}
fn dispose(&self) {
self.inner.dispose();
}
}
impl<T: Send + Sync + 'static> Trigger for WriteSignal<T> {
fn trigger(&self) {
if let Some(inner) = self.get_value() {
if let Some(inner) = self.inner.get() {
inner.trigger();
}
}
@ -89,6 +83,6 @@ impl<T: Send + Sync + 'static> UpdateUntracked for WriteSignal<T> {
&self,
fun: impl FnOnce(&mut Self::Value) -> U,
) -> Option<U> {
self.get_value().and_then(|n| n.try_update_untracked(fun))
self.inner.get().and_then(|n| n.try_update_untracked(fun))
}
}

View File

@ -81,6 +81,10 @@ macro_rules! unwrap_signal {
}};
}
pub trait Dispose {
fn dispose(self);
}
pub trait Track {
fn track(&self);
}

View File

@ -3,7 +3,7 @@ pub mod read {
computed::{ArcMemo, Memo},
owner::StoredValue,
signal::{ArcReadSignal, ReadSignal, RwSignal},
traits::{DefinedAt, Get, GetUntracked, With, WithUntracked},
traits::{DefinedAt, Dispose, Get, GetUntracked, With, WithUntracked},
untrack,
};
use std::{panic::Location, sync::Arc};
@ -140,6 +140,12 @@ pub mod read {
inner: StoredValue<SignalTypes<T>>,
}
impl<T: Send + Sync + 'static> Dispose for Signal<T> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<T> Clone for Signal<T> {
fn clone(&self) -> Self {
*self
@ -190,7 +196,7 @@ pub mod read {
fun: impl FnOnce(&Self::Value) -> U,
) -> Option<U> {
self.inner
.with_value(|inner| match &inner {
.try_with_value(|inner| match &inner {
SignalTypes::ReadSignal(i) => i.try_with_untracked(fun),
SignalTypes::Memo(i) => i.try_with_untracked(fun),
SignalTypes::DerivedSignal(i) => {
@ -212,7 +218,7 @@ pub mod read {
fun: impl FnOnce(&Self::Value) -> U,
) -> Option<U> {
self.inner
.with_value(|inner| match &inner {
.try_with_value(|inner| match &inner {
SignalTypes::ReadSignal(i) => i.try_with(fun),
SignalTypes::Memo(i) => i.try_with(fun),
SignalTypes::DerivedSignal(i) => Some(fun(&i())),