diff --git a/reactive_stores/src/arc_field.rs b/reactive_stores/src/arc_field.rs index b42beb919..4200f98e0 100644 --- a/reactive_stores/src/arc_field.rs +++ b/reactive_stores/src/arc_field.rs @@ -75,6 +75,7 @@ impl StoreField for ArcField { type Value = T; type Reader = StoreFieldReader; type Writer = StoreFieldWriter; + type UntrackedWriter = StoreFieldWriter; fn get_trigger(&self, path: StorePath) -> ArcTrigger { (self.get_trigger)(path) @@ -91,6 +92,12 @@ impl StoreField for ArcField { fn writer(&self) -> Option { (self.write)().map(StoreFieldWriter::new) } + + fn untracked_writer(&self) -> Option { + let mut writer = (self.write)().map(StoreFieldWriter::new)?; + writer.untrack(); + Some(writer) + } } impl From> for ArcField diff --git a/reactive_stores/src/field.rs b/reactive_stores/src/field.rs index bfac83066..b0748a081 100644 --- a/reactive_stores/src/field.rs +++ b/reactive_stores/src/field.rs @@ -27,6 +27,7 @@ where type Value = T; type Reader = StoreFieldReader; type Writer = StoreFieldWriter; + type UntrackedWriter = StoreFieldWriter; fn get_trigger(&self, path: StorePath) -> ArcTrigger { self.inner @@ -49,6 +50,12 @@ where fn writer(&self) -> Option { self.inner.try_get_value().and_then(|inner| inner.writer()) } + + fn untracked_writer(&self) -> Option { + self.inner + .try_get_value() + .and_then(|inner| inner.untracked_writer()) + } } impl From> for Field diff --git a/reactive_stores/src/iter.rs b/reactive_stores/src/iter.rs index 9da3aef7b..0a4edfcfc 100644 --- a/reactive_stores/src/iter.rs +++ b/reactive_stores/src/iter.rs @@ -77,6 +77,8 @@ where type Reader = MappedMutArc; type Writer = MappedMutArc, Prev::Output>; + type UntrackedWriter = + MappedMutArc, Prev::Output>; fn path(&self) -> impl IntoIterator { self.inner @@ -109,6 +111,12 @@ where move |n| &mut n[index], )) } + + fn untracked_writer(&self) -> Option { + let mut guard = self.writer()?; + guard.untrack(); + Some(guard) + } } impl DefinedAt for AtIndex diff --git a/reactive_stores/src/store_field.rs b/reactive_stores/src/store_field.rs index 5822ec5e3..e97d50743 100644 --- a/reactive_stores/src/store_field.rs +++ b/reactive_stores/src/store_field.rs @@ -2,23 +2,31 @@ use crate::{ path::{StorePath, StorePathSegment}, ArcStore, Store, }; -use guardian::ArcRwLockWriteGuardian; use or_poisoned::OrPoisoned; use reactive_graph::{ owner::Storage, signal::{ - guards::{Plain, WriteGuard}, + guards::{Mapped, MappedMut, Plain, UntrackedWriteGuard, WriteGuard}, ArcTrigger, }, - traits::{DefinedAt, UntrackableGuard}, + traits::{ + DefinedAt, IsDisposed, ReadUntracked, Track, Trigger, UntrackableGuard, + Writeable, + }, unwrap_signal, }; -use std::{iter, ops::Deref, sync::Arc}; +use std::{ + iter, + ops::{Deref, DerefMut}, + panic::Location, + sync::Arc, +}; pub trait StoreField: Sized { type Value; type Reader: Deref; type Writer: UntrackableGuard; + type UntrackedWriter: DerefMut; fn get_trigger(&self, path: StorePath) -> ArcTrigger; @@ -27,6 +35,23 @@ pub trait StoreField: Sized { fn reader(&self) -> Option; fn writer(&self) -> Option; + + fn untracked_writer(&self) -> Option; + + #[track_caller] + fn then( + self, + map_fn: fn(&Self::Value) -> &T, + map_fn_mut: fn(&mut Self::Value) -> &mut T, + ) -> Then { + Then { + #[cfg(debug_assertions)] + defined_at: Location::caller(), + inner: self, + map_fn, + map_fn_mut, + } + } } impl StoreField for ArcStore @@ -35,7 +60,8 @@ where { type Value = T; type Reader = Plain; - type Writer = WriteGuard>; + type Writer = WriteGuard>; + type UntrackedWriter = UntrackedWriteGuard; fn get_trigger(&self, path: StorePath) -> ArcTrigger { let triggers = &self.signals; @@ -53,10 +79,13 @@ where fn writer(&self) -> Option { let trigger = self.get_trigger(Default::default()); - let guard = - ArcRwLockWriteGuardian::take(Arc::clone(&self.value)).ok()?; + let guard = self.untracked_writer()?; Some(WriteGuard::new(trigger, guard)) } + + fn untracked_writer(&self) -> Option { + UntrackedWriteGuard::try_new(Arc::clone(&self.value)) + } } impl StoreField for Store @@ -66,7 +95,8 @@ where { type Value = T; type Reader = Plain; - type Writer = WriteGuard>; + type Writer = WriteGuard>; + type UntrackedWriter = UntrackedWriteGuard; fn get_trigger(&self, path: StorePath) -> ArcTrigger { self.inner @@ -89,4 +119,132 @@ where fn writer(&self) -> Option { self.inner.try_get_value().and_then(|n| n.writer()) } + + fn untracked_writer(&self) -> Option { + self.inner + .try_get_value() + .and_then(|n| n.untracked_writer()) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct Then +where + S: StoreField, +{ + inner: S, + map_fn: fn(&S::Value) -> &T, + map_fn_mut: fn(&mut S::Value) -> &mut T, + #[cfg(debug_assertions)] + defined_at: &'static Location<'static>, +} + +impl StoreField for Then +where + S: StoreField, +{ + type Value = T; + type Reader = Mapped; + type Writer = MappedMut; + type UntrackedWriter = MappedMut; + + fn get_trigger(&self, path: StorePath) -> ArcTrigger { + self.inner.get_trigger(path) + } + + fn path(&self) -> impl IntoIterator { + self.inner.path() + } + + fn reader(&self) -> Option { + let inner = self.inner.reader()?; + Some(Mapped::new_with_guard(inner, self.map_fn)) + } + + fn writer(&self) -> Option { + let inner = self.inner.writer()?; + Some(MappedMut::new(inner, self.map_fn, self.map_fn_mut)) + } + + fn untracked_writer(&self) -> Option { + let inner = self.inner.untracked_writer()?; + Some(MappedMut::new(inner, self.map_fn, self.map_fn_mut)) + } +} + +impl DefinedAt for Then +where + S: StoreField, +{ + fn defined_at(&self) -> Option<&'static Location<'static>> { + #[cfg(debug_assertions)] + { + Some(self.defined_at) + } + #[cfg(not(debug_assertions))] + { + None + } + } +} + +impl IsDisposed for Then +where + S: StoreField + IsDisposed, +{ + fn is_disposed(&self) -> bool { + self.inner.is_disposed() + } +} + +impl Trigger for Then +where + S: StoreField, +{ + fn trigger(&self) { + let trigger = self.get_trigger(self.path().into_iter().collect()); + trigger.trigger(); + } +} + +impl Track for Then +where + S: StoreField, +{ + fn track(&self) { + let trigger = self.get_trigger(self.path().into_iter().collect()); + trigger.track(); + } +} + +impl ReadUntracked for Then +where + S: StoreField, +{ + type Value = ::Reader; + + fn try_read_untracked(&self) -> Option { + self.reader() + } +} + +impl Writeable for Then +where + T: 'static, + S: StoreField, +{ + type Value = T; + + fn try_write(&self) -> Option> { + self.writer() + } + + fn try_write_untracked( + &self, + ) -> Option> { + self.writer().map(|mut writer| { + writer.untrack(); + writer + }) + } } diff --git a/reactive_stores/src/subfield.rs b/reactive_stores/src/subfield.rs index deca5fa14..00851e73c 100644 --- a/reactive_stores/src/subfield.rs +++ b/reactive_stores/src/subfield.rs @@ -80,7 +80,9 @@ where { type Value = T; type Reader = Mapped; - type Writer = MappedMut, T>; + type Writer = MappedMut, T>; + type UntrackedWriter = + MappedMut, T>; fn path(&self) -> impl IntoIterator { self.inner @@ -100,9 +102,15 @@ where fn writer(&self) -> Option { let trigger = self.get_trigger(self.path().into_iter().collect()); - let inner = WriteGuard::new(trigger, self.inner.writer()?); + let inner = WriteGuard::new(trigger, self.inner.untracked_writer()?); Some(MappedMut::new(inner, self.read, self.write)) } + + fn untracked_writer(&self) -> Option { + let mut guard = self.writer()?; + guard.untrack(); + Some(guard) + } } impl DefinedAt for Subfield