mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
fix/change: do not trigger every parent when writing to a store subfield
This commit is contained in:
parent
3d0fdb1ab0
commit
e8be9e31ff
5 changed files with 198 additions and 10 deletions
|
@ -75,6 +75,7 @@ impl<T> StoreField for ArcField<T> {
|
|||
type Value = T;
|
||||
type Reader = StoreFieldReader<T>;
|
||||
type Writer = StoreFieldWriter<T>;
|
||||
type UntrackedWriter = StoreFieldWriter<T>;
|
||||
|
||||
fn get_trigger(&self, path: StorePath) -> ArcTrigger {
|
||||
(self.get_trigger)(path)
|
||||
|
@ -91,6 +92,12 @@ impl<T> StoreField for ArcField<T> {
|
|||
fn writer(&self) -> Option<Self::Writer> {
|
||||
(self.write)().map(StoreFieldWriter::new)
|
||||
}
|
||||
|
||||
fn untracked_writer(&self) -> Option<Self::UntrackedWriter> {
|
||||
let mut writer = (self.write)().map(StoreFieldWriter::new)?;
|
||||
writer.untrack();
|
||||
Some(writer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, Prev, T> From<Subfield<Inner, Prev, T>> for ArcField<T>
|
||||
|
|
|
@ -27,6 +27,7 @@ where
|
|||
type Value = T;
|
||||
type Reader = StoreFieldReader<T>;
|
||||
type Writer = StoreFieldWriter<T>;
|
||||
type UntrackedWriter = StoreFieldWriter<T>;
|
||||
|
||||
fn get_trigger(&self, path: StorePath) -> ArcTrigger {
|
||||
self.inner
|
||||
|
@ -49,6 +50,12 @@ where
|
|||
fn writer(&self) -> Option<Self::Writer> {
|
||||
self.inner.try_get_value().and_then(|inner| inner.writer())
|
||||
}
|
||||
|
||||
fn untracked_writer(&self) -> Option<Self::UntrackedWriter> {
|
||||
self.inner
|
||||
.try_get_value()
|
||||
.and_then(|inner| inner.untracked_writer())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, Prev, T, S> From<Subfield<Inner, Prev, T>> for Field<T, S>
|
||||
|
|
|
@ -77,6 +77,8 @@ where
|
|||
type Reader = MappedMutArc<Inner::Reader, Prev::Output>;
|
||||
type Writer =
|
||||
MappedMutArc<WriteGuard<ArcTrigger, Inner::Writer>, Prev::Output>;
|
||||
type UntrackedWriter =
|
||||
MappedMutArc<WriteGuard<ArcTrigger, Inner::Writer>, Prev::Output>;
|
||||
|
||||
fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
|
||||
self.inner
|
||||
|
@ -109,6 +111,12 @@ where
|
|||
move |n| &mut n[index],
|
||||
))
|
||||
}
|
||||
|
||||
fn untracked_writer(&self) -> Option<Self::UntrackedWriter> {
|
||||
let mut guard = self.writer()?;
|
||||
guard.untrack();
|
||||
Some(guard)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, Prev> DefinedAt for AtIndex<Inner, Prev>
|
||||
|
|
|
@ -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<Target = Self::Value>;
|
||||
type Writer: UntrackableGuard<Target = Self::Value>;
|
||||
type UntrackedWriter: DerefMut<Target = Self::Value>;
|
||||
|
||||
fn get_trigger(&self, path: StorePath) -> ArcTrigger;
|
||||
|
||||
|
@ -27,6 +35,23 @@ pub trait StoreField: Sized {
|
|||
fn reader(&self) -> Option<Self::Reader>;
|
||||
|
||||
fn writer(&self) -> Option<Self::Writer>;
|
||||
|
||||
fn untracked_writer(&self) -> Option<Self::UntrackedWriter>;
|
||||
|
||||
#[track_caller]
|
||||
fn then<T>(
|
||||
self,
|
||||
map_fn: fn(&Self::Value) -> &T,
|
||||
map_fn_mut: fn(&mut Self::Value) -> &mut T,
|
||||
) -> Then<T, Self> {
|
||||
Then {
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: Location::caller(),
|
||||
inner: self,
|
||||
map_fn,
|
||||
map_fn_mut,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> StoreField for ArcStore<T>
|
||||
|
@ -35,7 +60,8 @@ where
|
|||
{
|
||||
type Value = T;
|
||||
type Reader = Plain<T>;
|
||||
type Writer = WriteGuard<ArcTrigger, ArcRwLockWriteGuardian<T>>;
|
||||
type Writer = WriteGuard<ArcTrigger, UntrackedWriteGuard<T>>;
|
||||
type UntrackedWriter = UntrackedWriteGuard<T>;
|
||||
|
||||
fn get_trigger(&self, path: StorePath) -> ArcTrigger {
|
||||
let triggers = &self.signals;
|
||||
|
@ -53,10 +79,13 @@ where
|
|||
|
||||
fn writer(&self) -> Option<Self::Writer> {
|
||||
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<Self::UntrackedWriter> {
|
||||
UntrackedWriteGuard::try_new(Arc::clone(&self.value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> StoreField for Store<T, S>
|
||||
|
@ -66,7 +95,8 @@ where
|
|||
{
|
||||
type Value = T;
|
||||
type Reader = Plain<T>;
|
||||
type Writer = WriteGuard<ArcTrigger, ArcRwLockWriteGuardian<T>>;
|
||||
type Writer = WriteGuard<ArcTrigger, UntrackedWriteGuard<T>>;
|
||||
type UntrackedWriter = UntrackedWriteGuard<T>;
|
||||
|
||||
fn get_trigger(&self, path: StorePath) -> ArcTrigger {
|
||||
self.inner
|
||||
|
@ -89,4 +119,132 @@ where
|
|||
fn writer(&self) -> Option<Self::Writer> {
|
||||
self.inner.try_get_value().and_then(|n| n.writer())
|
||||
}
|
||||
|
||||
fn untracked_writer(&self) -> Option<Self::UntrackedWriter> {
|
||||
self.inner
|
||||
.try_get_value()
|
||||
.and_then(|n| n.untracked_writer())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Then<T, S>
|
||||
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<T, S> StoreField for Then<T, S>
|
||||
where
|
||||
S: StoreField,
|
||||
{
|
||||
type Value = T;
|
||||
type Reader = Mapped<S::Reader, T>;
|
||||
type Writer = MappedMut<S::Writer, T>;
|
||||
type UntrackedWriter = MappedMut<S::UntrackedWriter, T>;
|
||||
|
||||
fn get_trigger(&self, path: StorePath) -> ArcTrigger {
|
||||
self.inner.get_trigger(path)
|
||||
}
|
||||
|
||||
fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
|
||||
self.inner.path()
|
||||
}
|
||||
|
||||
fn reader(&self) -> Option<Self::Reader> {
|
||||
let inner = self.inner.reader()?;
|
||||
Some(Mapped::new_with_guard(inner, self.map_fn))
|
||||
}
|
||||
|
||||
fn writer(&self) -> Option<Self::Writer> {
|
||||
let inner = self.inner.writer()?;
|
||||
Some(MappedMut::new(inner, self.map_fn, self.map_fn_mut))
|
||||
}
|
||||
|
||||
fn untracked_writer(&self) -> Option<Self::UntrackedWriter> {
|
||||
let inner = self.inner.untracked_writer()?;
|
||||
Some(MappedMut::new(inner, self.map_fn, self.map_fn_mut))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> DefinedAt for Then<T, S>
|
||||
where
|
||||
S: StoreField,
|
||||
{
|
||||
fn defined_at(&self) -> Option<&'static Location<'static>> {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
Some(self.defined_at)
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> IsDisposed for Then<T, S>
|
||||
where
|
||||
S: StoreField + IsDisposed,
|
||||
{
|
||||
fn is_disposed(&self) -> bool {
|
||||
self.inner.is_disposed()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Trigger for Then<T, S>
|
||||
where
|
||||
S: StoreField,
|
||||
{
|
||||
fn trigger(&self) {
|
||||
let trigger = self.get_trigger(self.path().into_iter().collect());
|
||||
trigger.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Track for Then<T, S>
|
||||
where
|
||||
S: StoreField,
|
||||
{
|
||||
fn track(&self) {
|
||||
let trigger = self.get_trigger(self.path().into_iter().collect());
|
||||
trigger.track();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> ReadUntracked for Then<T, S>
|
||||
where
|
||||
S: StoreField,
|
||||
{
|
||||
type Value = <Self as StoreField>::Reader;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.reader()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Writeable for Then<T, S>
|
||||
where
|
||||
T: 'static,
|
||||
S: StoreField,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
|
||||
self.writer()
|
||||
}
|
||||
|
||||
fn try_write_untracked(
|
||||
&self,
|
||||
) -> Option<impl DerefMut<Target = Self::Value>> {
|
||||
self.writer().map(|mut writer| {
|
||||
writer.untrack();
|
||||
writer
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,9 @@ where
|
|||
{
|
||||
type Value = T;
|
||||
type Reader = Mapped<Inner::Reader, T>;
|
||||
type Writer = MappedMut<WriteGuard<ArcTrigger, Inner::Writer>, T>;
|
||||
type Writer = MappedMut<WriteGuard<ArcTrigger, Inner::UntrackedWriter>, T>;
|
||||
type UntrackedWriter =
|
||||
MappedMut<WriteGuard<ArcTrigger, Inner::UntrackedWriter>, T>;
|
||||
|
||||
fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
|
||||
self.inner
|
||||
|
@ -100,9 +102,15 @@ where
|
|||
|
||||
fn writer(&self) -> Option<Self::Writer> {
|
||||
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<Self::UntrackedWriter> {
|
||||
let mut guard = self.writer()?;
|
||||
guard.untrack();
|
||||
Some(guard)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, Prev, T> DefinedAt for Subfield<Inner, Prev, T>
|
||||
|
|
Loading…
Reference in a new issue