smooth out StoredValue APIs
This commit is contained in:
parent
9818e7cb68
commit
d8d2fdac5d
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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::*;
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}*/
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,10 @@ macro_rules! unwrap_signal {
|
|||
}};
|
||||
}
|
||||
|
||||
pub trait Dispose {
|
||||
fn dispose(self);
|
||||
}
|
||||
|
||||
pub trait Track {
|
||||
fn track(&self);
|
||||
}
|
||||
|
|
|
@ -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())),
|
||||
|
|
Loading…
Reference in New Issue