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