reactive_stores/
keyed.rs

1use crate::{
2    path::{StorePath, StorePathSegment},
3    store_field::StoreField,
4    KeyMap, StoreFieldTrigger,
5};
6use reactive_graph::{
7    signal::{
8        guards::{Mapped, MappedMut, MappedMutArc, WriteGuard},
9        ArcTrigger,
10    },
11    traits::{
12        DefinedAt, IsDisposed, Notify, ReadUntracked, Track, UntrackableGuard,
13        Write,
14    },
15};
16use std::{
17    collections::VecDeque,
18    fmt::Debug,
19    hash::Hash,
20    iter,
21    ops::{Deref, DerefMut, IndexMut},
22    panic::Location,
23};
24
25/// Provides access to a subfield that contains some kind of keyed collection.
26#[derive(Debug)]
27pub struct KeyedSubfield<Inner, Prev, K, T>
28where
29    for<'a> &'a T: IntoIterator,
30{
31    #[cfg(any(debug_assertions, leptos_debuginfo))]
32    defined_at: &'static Location<'static>,
33    path_segment: StorePathSegment,
34    inner: Inner,
35    read: fn(&Prev) -> &T,
36    write: fn(&mut Prev) -> &mut T,
37    key_fn: fn(<&T as IntoIterator>::Item) -> K,
38}
39
40impl<Inner, Prev, K, T> Clone for KeyedSubfield<Inner, Prev, K, T>
41where
42    for<'a> &'a T: IntoIterator,
43    Inner: Clone,
44{
45    fn clone(&self) -> Self {
46        Self {
47            #[cfg(any(debug_assertions, leptos_debuginfo))]
48            defined_at: self.defined_at,
49            path_segment: self.path_segment,
50            inner: self.inner.clone(),
51            read: self.read,
52            write: self.write,
53            key_fn: self.key_fn,
54        }
55    }
56}
57
58impl<Inner, Prev, K, T> Copy for KeyedSubfield<Inner, Prev, K, T>
59where
60    for<'a> &'a T: IntoIterator,
61    Inner: Copy,
62{
63}
64
65impl<Inner, Prev, K, T> KeyedSubfield<Inner, Prev, K, T>
66where
67    for<'a> &'a T: IntoIterator,
68{
69    /// Creates a keyed subfield of the inner data type with the given key function.
70    #[track_caller]
71    pub fn new(
72        inner: Inner,
73        path_segment: StorePathSegment,
74        key_fn: fn(<&T as IntoIterator>::Item) -> K,
75        read: fn(&Prev) -> &T,
76        write: fn(&mut Prev) -> &mut T,
77    ) -> Self {
78        Self {
79            #[cfg(any(debug_assertions, leptos_debuginfo))]
80            defined_at: Location::caller(),
81            inner,
82            path_segment,
83            read,
84            write,
85            key_fn,
86        }
87    }
88}
89
90impl<Inner, Prev, K, T> StoreField for KeyedSubfield<Inner, Prev, K, T>
91where
92    Self: Clone,
93    for<'a> &'a T: IntoIterator,
94    Inner: StoreField<Value = Prev>,
95    Prev: 'static,
96    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
97{
98    type Value = T;
99    type Reader = Mapped<Inner::Reader, T>;
100    type Writer = MappedMut<WriteGuard<Vec<ArcTrigger>, Inner::Writer>, T>;
101
102    fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
103        self.inner
104            .path()
105            .into_iter()
106            .chain(iter::once(self.path_segment))
107    }
108
109    fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
110        self.inner.get_trigger(path)
111    }
112
113    fn reader(&self) -> Option<Self::Reader> {
114        let inner = self.inner.reader()?;
115        Some(Mapped::new_with_guard(inner, self.read))
116    }
117
118    fn writer(&self) -> Option<Self::Writer> {
119        let mut parent = self.inner.writer()?;
120        parent.untrack();
121        let triggers = self.triggers_for_current_path();
122        let guard = WriteGuard::new(triggers, parent);
123        Some(MappedMut::new(guard, self.read, self.write))
124    }
125
126    #[inline(always)]
127    fn keys(&self) -> Option<KeyMap> {
128        self.inner.keys()
129    }
130
131    fn track_field(&self) {
132        let inner = self
133            .inner
134            .get_trigger(self.inner.path().into_iter().collect());
135        inner.this.track();
136        let trigger = self.get_trigger(self.path().into_iter().collect());
137        trigger.this.track();
138        trigger.children.track();
139    }
140}
141
142impl<Inner, Prev, K, T> KeyedSubfield<Inner, Prev, K, T>
143where
144    Self: Clone,
145    for<'a> &'a T: IntoIterator,
146    Inner: StoreField<Value = Prev>,
147    Prev: 'static,
148    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
149{
150    fn latest_keys(&self) -> Vec<K> {
151        self.reader()
152            .map(|r| r.deref().into_iter().map(|n| (self.key_fn)(n)).collect())
153            .unwrap_or_default()
154    }
155}
156
157/// Gives keyed write access to a value in some collection.
158pub struct KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
159where
160    KeyedSubfield<Inner, Prev, K, T>: Clone,
161    for<'a> &'a T: IntoIterator,
162    Inner: StoreField<Value = Prev>,
163    Prev: 'static,
164    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
165{
166    inner: KeyedSubfield<Inner, Prev, K, T>,
167    guard: Option<Guard>,
168}
169
170impl<Inner, Prev, K, T, Guard> Deref
171    for KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
172where
173    Guard: Deref,
174    KeyedSubfield<Inner, Prev, K, T>: Clone,
175    for<'a> &'a T: IntoIterator,
176    Inner: StoreField<Value = Prev>,
177    Prev: 'static,
178    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
179{
180    type Target = Guard::Target;
181
182    fn deref(&self) -> &Self::Target {
183        self.guard
184            .as_ref()
185            .expect("should be Some(_) until dropped")
186            .deref()
187    }
188}
189
190impl<Inner, Prev, K, T, Guard> DerefMut
191    for KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
192where
193    Guard: DerefMut,
194    KeyedSubfield<Inner, Prev, K, T>: Clone,
195    for<'a> &'a T: IntoIterator,
196    Inner: StoreField<Value = Prev>,
197    Prev: 'static,
198    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
199{
200    fn deref_mut(&mut self) -> &mut Self::Target {
201        self.guard
202            .as_mut()
203            .expect("should be Some(_) until dropped")
204            .deref_mut()
205    }
206}
207
208impl<Inner, Prev, K, T, Guard> UntrackableGuard
209    for KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
210where
211    Guard: UntrackableGuard,
212    KeyedSubfield<Inner, Prev, K, T>: Clone,
213    for<'a> &'a T: IntoIterator,
214    Inner: StoreField<Value = Prev>,
215    Prev: 'static,
216    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
217{
218    fn untrack(&mut self) {
219        if let Some(inner) = self.guard.as_mut() {
220            inner.untrack();
221        }
222    }
223}
224
225impl<Inner, Prev, K, T, Guard> Drop
226    for KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
227where
228    KeyedSubfield<Inner, Prev, K, T>: Clone,
229    for<'a> &'a T: IntoIterator,
230    Inner: StoreField<Value = Prev>,
231    Prev: 'static,
232    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
233{
234    fn drop(&mut self) {
235        // dropping the inner guard will
236        // 1) synchronously release its write lock on the store's value
237        // 2) trigger an (asynchronous) reactive update
238        drop(self.guard.take());
239
240        // now that the write lock is release, we can get a read lock to refresh this keyed field
241        // based on the new value
242        self.inner.update_keys();
243        self.inner.notify();
244
245        // reactive updates happen on the next tick
246    }
247}
248
249impl<Inner, Prev, K, T> DefinedAt for KeyedSubfield<Inner, Prev, K, T>
250where
251    for<'a> &'a T: IntoIterator,
252    Inner: StoreField<Value = Prev>,
253{
254    fn defined_at(&self) -> Option<&'static Location<'static>> {
255        #[cfg(any(debug_assertions, leptos_debuginfo))]
256        {
257            Some(self.defined_at)
258        }
259        #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
260        {
261            None
262        }
263    }
264}
265
266impl<Inner, Prev, K, T> IsDisposed for KeyedSubfield<Inner, Prev, K, T>
267where
268    for<'a> &'a T: IntoIterator,
269    Inner: IsDisposed,
270{
271    fn is_disposed(&self) -> bool {
272        self.inner.is_disposed()
273    }
274}
275
276impl<Inner, Prev, K, T> Notify for KeyedSubfield<Inner, Prev, K, T>
277where
278    Self: Clone,
279    for<'a> &'a T: IntoIterator,
280    Inner: StoreField<Value = Prev>,
281    Prev: 'static,
282    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
283{
284    fn notify(&self) {
285        let trigger = self.get_trigger(self.path().into_iter().collect());
286        trigger.this.notify();
287        trigger.children.notify();
288    }
289}
290
291impl<Inner, Prev, K, T> Track for KeyedSubfield<Inner, Prev, K, T>
292where
293    Self: Clone,
294    for<'a> &'a T: IntoIterator,
295    Inner: StoreField<Value = Prev> + Track + 'static,
296    Prev: 'static,
297    T: 'static,
298    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
299{
300    fn track(&self) {
301        self.track_field();
302    }
303}
304
305impl<Inner, Prev, K, T> ReadUntracked for KeyedSubfield<Inner, Prev, K, T>
306where
307    Self: Clone,
308    for<'a> &'a T: IntoIterator,
309    Inner: StoreField<Value = Prev>,
310    Prev: 'static,
311    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
312{
313    type Value = <Self as StoreField>::Reader;
314
315    fn try_read_untracked(&self) -> Option<Self::Value> {
316        self.reader()
317    }
318}
319
320impl<Inner, Prev, K, T> Write for KeyedSubfield<Inner, Prev, K, T>
321where
322    Self: Clone,
323    for<'a> &'a T: IntoIterator,
324    T: 'static,
325    Inner: StoreField<Value = Prev>,
326    Prev: 'static,
327    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
328{
329    type Value = T;
330
331    fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
332        let guard = self.writer()?;
333        Some(KeyedSubfieldWriteGuard {
334            inner: self.clone(),
335            guard: Some(guard),
336        })
337    }
338
339    fn try_write_untracked(
340        &self,
341    ) -> Option<impl DerefMut<Target = Self::Value>> {
342        let mut guard = self.writer()?;
343        guard.untrack();
344        Some(KeyedSubfieldWriteGuard {
345            inner: self.clone(),
346            guard: Some(guard),
347        })
348    }
349}
350
351/// Gives access to the value in a collection based on some key.
352#[derive(Debug)]
353pub struct AtKeyed<Inner, Prev, K, T>
354where
355    for<'a> &'a T: IntoIterator,
356{
357    #[cfg(any(debug_assertions, leptos_debuginfo))]
358    defined_at: &'static Location<'static>,
359    inner: KeyedSubfield<Inner, Prev, K, T>,
360    key: K,
361}
362
363impl<Inner, Prev, K, T> Clone for AtKeyed<Inner, Prev, K, T>
364where
365    for<'a> &'a T: IntoIterator,
366    KeyedSubfield<Inner, Prev, K, T>: Clone,
367    K: Debug + Clone,
368{
369    fn clone(&self) -> Self {
370        Self {
371            #[cfg(any(debug_assertions, leptos_debuginfo))]
372            defined_at: self.defined_at,
373            inner: self.inner.clone(),
374            key: self.key.clone(),
375        }
376    }
377}
378
379impl<Inner, Prev, K, T> Copy for AtKeyed<Inner, Prev, K, T>
380where
381    for<'a> &'a T: IntoIterator,
382    KeyedSubfield<Inner, Prev, K, T>: Copy,
383    K: Debug + Copy,
384{
385}
386
387impl<Inner, Prev, K, T> AtKeyed<Inner, Prev, K, T>
388where
389    for<'a> &'a T: IntoIterator,
390{
391    /// Provides access to the item in the inner collection at this key.
392    #[track_caller]
393    pub fn new(inner: KeyedSubfield<Inner, Prev, K, T>, key: K) -> Self {
394        Self {
395            #[cfg(any(debug_assertions, leptos_debuginfo))]
396            defined_at: Location::caller(),
397            inner,
398            key,
399        }
400    }
401}
402
403impl<Inner, Prev, K, T> StoreField for AtKeyed<Inner, Prev, K, T>
404where
405    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
406    KeyedSubfield<Inner, Prev, K, T>: Clone,
407    for<'a> &'a T: IntoIterator,
408    Inner: StoreField<Value = Prev>,
409    Prev: 'static,
410    T: IndexMut<usize>,
411    T::Output: Sized,
412{
413    type Value = T::Output;
414    type Reader = MappedMutArc<
415        <KeyedSubfield<Inner, Prev, K, T> as StoreField>::Reader,
416        T::Output,
417    >;
418    type Writer = WriteGuard<
419        Vec<ArcTrigger>,
420        MappedMutArc<
421            <KeyedSubfield<Inner, Prev, K, T> as StoreField>::Writer,
422            T::Output,
423        >,
424    >;
425
426    fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
427        let inner = self.inner.path().into_iter().collect::<StorePath>();
428        let keys = self
429            .inner
430            .keys()
431            .expect("using keys on a store with no keys");
432        let this = keys
433            .with_field_keys(
434                inner.clone(),
435                |keys| keys.get(&self.key),
436                || self.inner.latest_keys(),
437            )
438            .flatten()
439            .map(|(path, _)| path);
440        inner.into_iter().chain(this)
441    }
442
443    fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
444        self.inner.get_trigger(path)
445    }
446
447    fn reader(&self) -> Option<Self::Reader> {
448        let inner = self.inner.reader()?;
449
450        let inner_path = self.inner.path().into_iter().collect();
451        let keys = self.inner.keys()?;
452        let index = keys
453            .with_field_keys(
454                inner_path,
455                |keys| keys.get(&self.key),
456                || self.inner.latest_keys(),
457            )
458            .flatten()
459            .map(|(_, idx)| idx)?;
460
461        Some(MappedMutArc::new(
462            inner,
463            move |n| &n[index],
464            move |n| &mut n[index],
465        ))
466    }
467
468    fn writer(&self) -> Option<Self::Writer> {
469        let mut inner = self.inner.writer()?;
470        inner.untrack();
471        let inner_path = self.inner.path().into_iter().collect::<StorePath>();
472        let keys = self
473            .inner
474            .keys()
475            .expect("using keys on a store with no keys");
476        let index = keys
477            .with_field_keys(
478                inner_path.clone(),
479                |keys| keys.get(&self.key),
480                || self.inner.latest_keys(),
481            )
482            .flatten()
483            .map(|(_, idx)| idx)?;
484
485        let triggers = self.triggers_for_current_path();
486
487        Some(WriteGuard::new(
488            triggers,
489            MappedMutArc::new(
490                inner,
491                move |n| &n[index],
492                move |n| &mut n[index],
493            ),
494        ))
495    }
496
497    #[inline(always)]
498    fn keys(&self) -> Option<KeyMap> {
499        self.inner.keys()
500    }
501}
502
503impl<Inner, Prev, K, T> DefinedAt for AtKeyed<Inner, Prev, K, T>
504where
505    for<'a> &'a T: IntoIterator,
506{
507    fn defined_at(&self) -> Option<&'static Location<'static>> {
508        #[cfg(any(debug_assertions, leptos_debuginfo))]
509        {
510            Some(self.defined_at)
511        }
512        #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
513        {
514            None
515        }
516    }
517}
518
519impl<Inner, Prev, K, T> IsDisposed for AtKeyed<Inner, Prev, K, T>
520where
521    for<'a> &'a T: IntoIterator,
522    Inner: IsDisposed,
523{
524    fn is_disposed(&self) -> bool {
525        self.inner.is_disposed()
526    }
527}
528
529impl<Inner, Prev, K, T> Notify for AtKeyed<Inner, Prev, K, T>
530where
531    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
532    KeyedSubfield<Inner, Prev, K, T>: Clone,
533    for<'a> &'a T: IntoIterator,
534    Inner: StoreField<Value = Prev>,
535    Prev: 'static,
536    T: IndexMut<usize>,
537    T::Output: Sized,
538{
539    fn notify(&self) {
540        let trigger = self.get_trigger(self.path().into_iter().collect());
541        trigger.this.notify();
542        trigger.children.notify();
543    }
544}
545
546impl<Inner, Prev, K, T> Track for AtKeyed<Inner, Prev, K, T>
547where
548    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
549    KeyedSubfield<Inner, Prev, K, T>: Clone,
550    for<'a> &'a T: IntoIterator,
551    Inner: StoreField<Value = Prev>,
552    Prev: 'static,
553    T: IndexMut<usize>,
554    T::Output: Sized,
555{
556    fn track(&self) {
557        self.track_field();
558    }
559}
560
561impl<Inner, Prev, K, T> ReadUntracked for AtKeyed<Inner, Prev, K, T>
562where
563    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
564    KeyedSubfield<Inner, Prev, K, T>: Clone,
565    for<'a> &'a T: IntoIterator,
566    Inner: StoreField<Value = Prev>,
567    Prev: 'static,
568    T: IndexMut<usize>,
569    T::Output: Sized,
570{
571    type Value = <Self as StoreField>::Reader;
572
573    fn try_read_untracked(&self) -> Option<Self::Value> {
574        self.reader()
575    }
576}
577
578impl<Inner, Prev, K, T> Write for AtKeyed<Inner, Prev, K, T>
579where
580    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
581    KeyedSubfield<Inner, Prev, K, T>: Clone,
582    for<'a> &'a T: IntoIterator,
583    Inner: StoreField<Value = Prev>,
584    Prev: 'static,
585    T: IndexMut<usize>,
586    T::Output: Sized + 'static,
587{
588    type Value = T::Output;
589
590    fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
591        self.writer()
592    }
593
594    fn try_write_untracked(
595        &self,
596    ) -> Option<impl DerefMut<Target = Self::Value>> {
597        self.writer().map(|mut writer| {
598            writer.untrack();
599            writer
600        })
601    }
602}
603
604impl<Inner, Prev, K, T> KeyedSubfield<Inner, Prev, K, T>
605where
606    Self: Clone,
607    for<'a> &'a T: IntoIterator,
608    Inner: StoreField<Value = Prev>,
609    Prev: 'static,
610    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
611{
612    /// Generates a new set of keys and registers those keys with the parent store.
613    pub fn update_keys(&self) {
614        let inner_path = self.path().into_iter().collect();
615        let keys = self
616            .inner
617            .keys()
618            .expect("updating keys on a store with no keys");
619
620        // generating the latest keys out here means that if we have
621        // nested keyed fields, the second field will not try to take a
622        // read-lock on the key map to get the field while the first field
623        // is still holding the write-lock in the closure below
624        let latest = self.latest_keys();
625        keys.with_field_keys(
626            inner_path,
627            |keys| {
628                keys.update(latest);
629            },
630            || self.latest_keys(),
631        );
632    }
633}
634
635impl<Inner, Prev, K, T> IntoIterator for KeyedSubfield<Inner, Prev, K, T>
636where
637    Self: Clone,
638    for<'a> &'a T: IntoIterator,
639    Inner: Clone + StoreField<Value = Prev> + 'static,
640    Prev: 'static,
641    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
642    T: IndexMut<usize> + 'static,
643    T::Output: Sized,
644{
645    type Item = AtKeyed<Inner, Prev, K, T>;
646    type IntoIter = StoreFieldKeyedIter<Inner, Prev, K, T>;
647
648    #[track_caller]
649    fn into_iter(self) -> StoreFieldKeyedIter<Inner, Prev, K, T> {
650        // reactively track changes to this field
651        self.update_keys();
652        self.track_field();
653
654        // get the current length of the field by accessing slice
655        let reader = self.reader();
656
657        let keys = reader
658            .map(|r| {
659                r.into_iter()
660                    .map(|item| (self.key_fn)(item))
661                    .collect::<VecDeque<_>>()
662            })
663            .unwrap_or_default();
664
665        // return the iterator
666        StoreFieldKeyedIter { inner: self, keys }
667    }
668}
669
670/// An iterator over a [`KeyedSubfield`].
671pub struct StoreFieldKeyedIter<Inner, Prev, K, T>
672where
673    for<'a> &'a T: IntoIterator,
674    T: IndexMut<usize>,
675{
676    inner: KeyedSubfield<Inner, Prev, K, T>,
677    keys: VecDeque<K>,
678}
679
680impl<Inner, Prev, K, T> Iterator for StoreFieldKeyedIter<Inner, Prev, K, T>
681where
682    Inner: StoreField<Value = Prev> + Clone + 'static,
683    T: IndexMut<usize> + 'static,
684    T::Output: Sized + 'static,
685    for<'a> &'a T: IntoIterator,
686{
687    type Item = AtKeyed<Inner, Prev, K, T>;
688
689    fn next(&mut self) -> Option<Self::Item> {
690        self.keys
691            .pop_front()
692            .map(|key| AtKeyed::new(self.inner.clone(), key))
693    }
694}
695
696impl<Inner, Prev, K, T> DoubleEndedIterator
697    for StoreFieldKeyedIter<Inner, Prev, K, T>
698where
699    Inner: StoreField<Value = Prev> + Clone + 'static,
700    T: IndexMut<usize> + 'static,
701    T::Output: Sized + 'static,
702    for<'a> &'a T: IntoIterator,
703{
704    fn next_back(&mut self) -> Option<Self::Item> {
705        self.keys
706            .pop_back()
707            .map(|key| AtKeyed::new(self.inner.clone(), key))
708    }
709}