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, Index, IndexMut},
22 panic::Location,
23};
24
25pub trait KeyedAccess<K> {
32 type Value;
34 fn keyed(&self, index: usize, key: &K) -> &Self::Value;
36 fn keyed_mut(&mut self, index: usize, key: &K) -> &mut Self::Value;
38}
39impl<K, T> KeyedAccess<K> for VecDeque<T> {
40 type Value = T;
41 fn keyed(&self, index: usize, _key: &K) -> &Self::Value {
42 self.index(index)
43 }
44 fn keyed_mut(&mut self, index: usize, _key: &K) -> &mut Self::Value {
45 self.index_mut(index)
46 }
47}
48impl<K, T> KeyedAccess<K> for Vec<T> {
49 type Value = T;
50 fn keyed(&self, index: usize, _key: &K) -> &Self::Value {
51 self.index(index)
52 }
53 fn keyed_mut(&mut self, index: usize, _key: &K) -> &mut Self::Value {
54 self.index_mut(index)
55 }
56}
57impl<K, T> KeyedAccess<K> for [T] {
58 type Value = T;
59 fn keyed(&self, index: usize, _key: &K) -> &Self::Value {
60 self.index(index)
61 }
62 fn keyed_mut(&mut self, index: usize, _key: &K) -> &mut Self::Value {
63 self.index_mut(index)
64 }
65}
66impl<K: Ord, V> KeyedAccess<K> for std::collections::BTreeMap<K, V> {
67 type Value = V;
68 fn keyed(&self, _index: usize, key: &K) -> &Self::Value {
69 self.get(key).expect("key does not exist")
70 }
71 fn keyed_mut(&mut self, _index: usize, key: &K) -> &mut Self::Value {
72 self.get_mut(key).expect("key does not exist")
73 }
74}
75impl<K: Hash + Eq, V> KeyedAccess<K> for std::collections::HashMap<K, V> {
76 type Value = V;
77 fn keyed(&self, _index: usize, key: &K) -> &Self::Value {
78 self.get(key).expect("key does not exist")
79 }
80 fn keyed_mut(&mut self, _index: usize, key: &K) -> &mut Self::Value {
81 self.get_mut(key).expect("key does not exist")
82 }
83}
84
85#[derive(Debug)]
87pub struct KeyedSubfield<Inner, Prev, K, T>
88where
89 for<'a> &'a T: IntoIterator,
90{
91 #[cfg(any(debug_assertions, leptos_debuginfo))]
92 defined_at: &'static Location<'static>,
93 path_segment: StorePathSegment,
94 inner: Inner,
95 read: fn(&Prev) -> &T,
96 write: fn(&mut Prev) -> &mut T,
97 pub(crate) key_fn: fn(<&T as IntoIterator>::Item) -> K,
98}
99
100impl<Inner, Prev, K, T> Clone for KeyedSubfield<Inner, Prev, K, T>
101where
102 for<'a> &'a T: IntoIterator,
103 Inner: Clone,
104{
105 fn clone(&self) -> Self {
106 Self {
107 #[cfg(any(debug_assertions, leptos_debuginfo))]
108 defined_at: self.defined_at,
109 path_segment: self.path_segment,
110 inner: self.inner.clone(),
111 read: self.read,
112 write: self.write,
113 key_fn: self.key_fn,
114 }
115 }
116}
117
118impl<Inner, Prev, K, T> Copy for KeyedSubfield<Inner, Prev, K, T>
119where
120 for<'a> &'a T: IntoIterator,
121 Inner: Copy,
122{
123}
124
125impl<Inner, Prev, K, T> KeyedSubfield<Inner, Prev, K, T>
126where
127 for<'a> &'a T: IntoIterator,
128{
129 #[track_caller]
131 pub fn new(
132 inner: Inner,
133 path_segment: StorePathSegment,
134 key_fn: fn(<&T as IntoIterator>::Item) -> K,
135 read: fn(&Prev) -> &T,
136 write: fn(&mut Prev) -> &mut T,
137 ) -> Self {
138 Self {
139 #[cfg(any(debug_assertions, leptos_debuginfo))]
140 defined_at: Location::caller(),
141 inner,
142 path_segment,
143 read,
144 write,
145 key_fn,
146 }
147 }
148}
149
150impl<Inner, Prev, K, T> StoreField for KeyedSubfield<Inner, Prev, K, T>
151where
152 Self: Clone,
153 for<'a> &'a T: IntoIterator,
154 Inner: StoreField<Value = Prev>,
155 Prev: 'static,
156 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
157{
158 type Value = T;
159 type Reader = Mapped<Inner::Reader, T>;
160 type Writer = MappedMut<WriteGuard<Vec<ArcTrigger>, Inner::Writer>, T>;
161
162 fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
163 self.inner
164 .path()
165 .into_iter()
166 .chain(iter::once(self.path_segment))
167 }
168
169 fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
170 self.inner
171 .path_unkeyed()
172 .into_iter()
173 .chain(iter::once(self.path_segment))
174 }
175
176 fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
177 self.inner.get_trigger(path)
178 }
179
180 fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
181 self.inner.get_trigger_unkeyed(path)
182 }
183
184 fn reader(&self) -> Option<Self::Reader> {
185 let inner = self.inner.reader()?;
186 Some(Mapped::new_with_guard(inner, self.read))
187 }
188
189 fn writer(&self) -> Option<Self::Writer> {
190 let mut parent = self.inner.writer()?;
191 parent.untrack();
192 let triggers = self.triggers_for_current_path();
193 let guard = WriteGuard::new(triggers, parent);
194 Some(MappedMut::new(guard, self.read, self.write))
195 }
196
197 #[inline(always)]
198 fn keys(&self) -> Option<KeyMap> {
199 self.inner.keys()
200 }
201
202 fn track_field(&self) {
203 let mut full_path = self.path().into_iter().collect::<StorePath>();
204 let trigger = self.get_trigger(self.path().into_iter().collect());
205 trigger.this.track();
206 trigger.children.track();
207
208 while !full_path.is_empty() {
213 full_path.pop();
214 let inner = self.get_trigger(full_path.clone());
215 inner.this.track();
216 }
217 }
218}
219
220impl<Inner, Prev, K, T> KeyedSubfield<Inner, Prev, K, T>
221where
222 Self: Clone,
223 for<'a> &'a T: IntoIterator,
224 Inner: StoreField<Value = Prev>,
225 Prev: 'static,
226 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
227{
228 fn latest_keys(&self) -> Vec<K> {
229 self.reader()
230 .map(|r| r.deref().into_iter().map(|n| (self.key_fn)(n)).collect())
231 .unwrap_or_default()
232 }
233
234 pub(crate) fn path_at_key(
235 &self,
236 base_path: &StorePath,
237 key: &K,
238 ) -> Option<StorePath> {
239 let keys = self.keys();
240 let keys = keys.as_ref()?;
241 let segment = keys
242 .with_field_keys(
243 base_path.clone(),
244 |keys| (keys.get(key), vec![]),
245 || self.latest_keys(),
246 )
247 .flatten()
248 .map(|(_, idx)| idx)?;
249 let mut path = base_path.clone();
250 path.push(segment);
251 Some(path)
252 }
253}
254
255impl<Inner, Prev, K, T> KeyedSubfield<Inner, Prev, K, T>
256where
257 Self: Clone,
258 for<'a> &'a T: IntoIterator,
259 Inner: StoreField<Value = Prev>,
260{
261 pub fn at_key(&self, key: K) -> AtKeyed<Inner, Prev, K, T> {
263 AtKeyed::new(self.clone(), key)
264 }
265}
266
267pub struct KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
269where
270 KeyedSubfield<Inner, Prev, K, T>: Clone,
271 for<'a> &'a T: IntoIterator,
272 Inner: StoreField<Value = Prev>,
273 Prev: 'static,
274 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
275{
276 inner: KeyedSubfield<Inner, Prev, K, T>,
277 guard: Option<Guard>,
278 untracked: bool,
279}
280
281impl<Inner, Prev, K, T, Guard> Deref
282 for KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
283where
284 Guard: Deref,
285 KeyedSubfield<Inner, Prev, K, T>: Clone,
286 for<'a> &'a T: IntoIterator,
287 Inner: StoreField<Value = Prev>,
288 Prev: 'static,
289 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
290{
291 type Target = Guard::Target;
292
293 fn deref(&self) -> &Self::Target {
294 self.guard
295 .as_ref()
296 .expect("should be Some(_) until dropped")
297 .deref()
298 }
299}
300
301impl<Inner, Prev, K, T, Guard> DerefMut
302 for KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
303where
304 Guard: DerefMut,
305 KeyedSubfield<Inner, Prev, K, T>: Clone,
306 for<'a> &'a T: IntoIterator,
307 Inner: StoreField<Value = Prev>,
308 Prev: 'static,
309 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
310{
311 fn deref_mut(&mut self) -> &mut Self::Target {
312 self.guard
313 .as_mut()
314 .expect("should be Some(_) until dropped")
315 .deref_mut()
316 }
317}
318
319impl<Inner, Prev, K, T, Guard> UntrackableGuard
320 for KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
321where
322 Guard: UntrackableGuard,
323 KeyedSubfield<Inner, Prev, K, T>: Clone,
324 for<'a> &'a T: IntoIterator,
325 Inner: StoreField<Value = Prev>,
326 Prev: 'static,
327 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
328{
329 fn untrack(&mut self) {
330 self.untracked = true;
331 if let Some(inner) = self.guard.as_mut() {
332 inner.untrack();
333 }
334 }
335}
336
337impl<Inner, Prev, K, T, Guard> Drop
338 for KeyedSubfieldWriteGuard<Inner, Prev, K, T, Guard>
339where
340 KeyedSubfield<Inner, Prev, K, T>: Clone,
341 for<'a> &'a T: IntoIterator,
342 Inner: StoreField<Value = Prev>,
343 Prev: 'static,
344 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
345{
346 fn drop(&mut self) {
347 drop(self.guard.take());
351
352 self.inner.update_keys();
355
356 if !self.untracked {
357 self.inner.notify();
358 }
359
360 }
362}
363
364impl<Inner, Prev, K, T> DefinedAt for KeyedSubfield<Inner, Prev, K, T>
365where
366 for<'a> &'a T: IntoIterator,
367 Inner: StoreField<Value = Prev>,
368{
369 fn defined_at(&self) -> Option<&'static Location<'static>> {
370 #[cfg(any(debug_assertions, leptos_debuginfo))]
371 {
372 Some(self.defined_at)
373 }
374 #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
375 {
376 None
377 }
378 }
379}
380
381impl<Inner, Prev, K, T> IsDisposed for KeyedSubfield<Inner, Prev, K, T>
382where
383 for<'a> &'a T: IntoIterator,
384 Inner: IsDisposed,
385{
386 fn is_disposed(&self) -> bool {
387 self.inner.is_disposed()
388 }
389}
390
391impl<Inner, Prev, K, T> Notify for KeyedSubfield<Inner, Prev, K, T>
392where
393 Self: Clone,
394 for<'a> &'a T: IntoIterator,
395 Inner: StoreField<Value = Prev>,
396 Prev: 'static,
397 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
398{
399 fn notify(&self) {
400 let trigger = self.get_trigger(self.path().into_iter().collect());
401 trigger.this.notify();
402 trigger.children.notify();
403 }
404}
405
406impl<Inner, Prev, K, T> Track for KeyedSubfield<Inner, Prev, K, T>
407where
408 Self: Clone,
409 for<'a> &'a T: IntoIterator,
410 Inner: StoreField<Value = Prev> + Track + 'static,
411 Prev: 'static,
412 T: 'static,
413 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
414{
415 fn track(&self) {
416 self.track_field();
417 }
418}
419
420impl<Inner, Prev, K, T> ReadUntracked for KeyedSubfield<Inner, Prev, K, T>
421where
422 Self: Clone,
423 for<'a> &'a T: IntoIterator,
424 Inner: StoreField<Value = Prev>,
425 Prev: 'static,
426 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
427{
428 type Value = <Self as StoreField>::Reader;
429
430 fn try_read_untracked(&self) -> Option<Self::Value> {
431 self.reader()
432 }
433}
434
435impl<Inner, Prev, K, T> Write for KeyedSubfield<Inner, Prev, K, T>
436where
437 Self: Clone,
438 for<'a> &'a T: IntoIterator,
439 T: 'static,
440 Inner: StoreField<Value = Prev>,
441 Prev: 'static,
442 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
443{
444 type Value = T;
445
446 fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
447 let guard = self.writer()?;
448 Some(KeyedSubfieldWriteGuard {
449 inner: self.clone(),
450 guard: Some(guard),
451 untracked: false,
452 })
453 }
454
455 fn try_write_untracked(
456 &self,
457 ) -> Option<impl DerefMut<Target = Self::Value>> {
458 let mut guard = self.writer()?;
459 guard.untrack();
460 Some(KeyedSubfieldWriteGuard {
461 inner: self.clone(),
462 guard: Some(guard),
463 untracked: true,
464 })
465 }
466}
467
468#[derive(Debug)]
470pub struct AtKeyed<Inner, Prev, K, T>
471where
472 for<'a> &'a T: IntoIterator,
473{
474 #[cfg(any(debug_assertions, leptos_debuginfo))]
475 defined_at: &'static Location<'static>,
476 inner: KeyedSubfield<Inner, Prev, K, T>,
477 key: K,
478}
479
480impl<Inner, Prev, K, T> AtKeyed<Inner, Prev, K, T>
481where
482 for<'a> &'a T: IntoIterator,
483 K: Clone,
484{
485 pub fn key(&self) -> K {
487 self.key.clone()
488 }
489}
490
491impl<Inner, Prev, K, T> Clone for AtKeyed<Inner, Prev, K, T>
492where
493 for<'a> &'a T: IntoIterator,
494 KeyedSubfield<Inner, Prev, K, T>: Clone,
495 K: Debug + Clone,
496{
497 fn clone(&self) -> Self {
498 Self {
499 #[cfg(any(debug_assertions, leptos_debuginfo))]
500 defined_at: self.defined_at,
501 inner: self.inner.clone(),
502 key: self.key.clone(),
503 }
504 }
505}
506
507impl<Inner, Prev, K, T> Copy for AtKeyed<Inner, Prev, K, T>
508where
509 for<'a> &'a T: IntoIterator,
510 KeyedSubfield<Inner, Prev, K, T>: Copy,
511 K: Debug + Copy,
512{
513}
514
515impl<Inner, Prev, K, T> AtKeyed<Inner, Prev, K, T>
516where
517 for<'a> &'a T: IntoIterator,
518{
519 #[track_caller]
521 pub fn new(inner: KeyedSubfield<Inner, Prev, K, T>, key: K) -> Self {
522 Self {
523 #[cfg(any(debug_assertions, leptos_debuginfo))]
524 defined_at: Location::caller(),
525 inner,
526 key,
527 }
528 }
529}
530
531impl<Inner, Prev, K, T> AtKeyed<Inner, Prev, K, T>
532where
533 K: Clone + Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
534 KeyedSubfield<Inner, Prev, K, T>: Clone,
535 for<'a> &'a T: IntoIterator,
536 Inner: StoreField<Value = Prev>,
537 Prev: 'static,
538 T: KeyedAccess<K>,
539 T::Value: Sized,
540{
541 fn resolve_index(&self) -> Option<usize> {
543 let inner_path = self.inner.path().into_iter().collect();
544 let keys = self.inner.keys()?;
545 keys.with_field_keys(
546 inner_path,
547 |keys| (keys.get(&self.key), vec![]),
548 || self.inner.latest_keys(),
549 )
550 .flatten()
551 .map(|(_, idx)| idx)
552 }
553}
554
555impl<Inner, Prev, K, T> StoreField for AtKeyed<Inner, Prev, K, T>
556where
557 K: Clone + Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
558 KeyedSubfield<Inner, Prev, K, T>: Clone,
559 for<'a> &'a T: IntoIterator,
560 Inner: StoreField<Value = Prev>,
561 Prev: 'static,
562 T: KeyedAccess<K>,
563 T::Value: Sized,
564{
565 type Value = T::Value;
566 type Reader = MappedMutArc<
567 <KeyedSubfield<Inner, Prev, K, T> as StoreField>::Reader,
568 T::Value,
569 >;
570 type Writer = WriteGuard<
571 Vec<ArcTrigger>,
572 MappedMutArc<
573 <KeyedSubfield<Inner, Prev, K, T> as StoreField>::Writer,
574 T::Value,
575 >,
576 >;
577
578 fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
579 let inner = self.inner.path().into_iter().collect::<StorePath>();
580 let keys = self
581 .inner
582 .keys()
583 .expect("using keys on a store with no keys");
584 let this = keys
585 .with_field_keys(
586 inner.clone(),
587 |keys| (keys.get(&self.key), vec![]),
588 || self.inner.latest_keys(),
589 )
590 .flatten()
591 .map(|(path, _)| path);
592 inner.into_iter().chain(this)
593 }
594
595 fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
596 let inner =
597 self.inner.path_unkeyed().into_iter().collect::<StorePath>();
598 let keys = self
599 .inner
600 .keys()
601 .expect("using keys on a store with no keys");
602 let this = keys
603 .with_field_keys(
604 inner.clone(),
605 |keys| (keys.get(&self.key), vec![]),
606 || self.inner.latest_keys(),
607 )
608 .flatten()
609 .map(|(_, idx)| StorePathSegment(idx));
610 inner.into_iter().chain(this)
611 }
612
613 fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
614 self.inner.get_trigger(path)
615 }
616
617 fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
618 self.inner.get_trigger_unkeyed(path)
619 }
620
621 fn reader(&self) -> Option<Self::Reader> {
622 let inner = self.inner.reader()?;
623 let index = self.resolve_index()?;
624 Some(MappedMutArc::new(
625 inner,
626 {
627 let key = self.key.clone();
628 move |n| n.keyed(index, &key)
629 },
630 {
631 let key = self.key.clone();
632 move |n| n.keyed_mut(index, &key)
633 },
634 ))
635 }
636
637 fn writer(&self) -> Option<Self::Writer> {
638 let mut inner = self.inner.writer()?;
639 inner.untrack();
640 let index = self.resolve_index()?;
641 let triggers = self.triggers_for_current_path();
642 Some(WriteGuard::new(
643 triggers,
644 MappedMutArc::new(
645 inner,
646 {
647 let key = self.key.clone();
648 move |n| n.keyed(index, &key)
649 },
650 {
651 let key = self.key.clone();
652 move |n| n.keyed_mut(index, &key)
653 },
654 ),
655 ))
656 }
657
658 #[inline(always)]
659 fn keys(&self) -> Option<KeyMap> {
660 self.inner.keys()
661 }
662
663 fn track_field(&self) {
664 let mut full_path = self.path().into_iter().collect::<StorePath>();
665 let trigger = self.get_trigger(self.path().into_iter().collect());
666 trigger.this.track();
667 trigger.children.track();
668
669 while !full_path.is_empty() {
674 full_path.pop();
675 let inner = self.get_trigger(full_path.clone());
676 inner.this.track();
677 }
678 }
679}
680
681impl<Inner, Prev, K, T> DefinedAt for AtKeyed<Inner, Prev, K, T>
682where
683 for<'a> &'a T: IntoIterator,
684{
685 fn defined_at(&self) -> Option<&'static Location<'static>> {
686 #[cfg(any(debug_assertions, leptos_debuginfo))]
687 {
688 Some(self.defined_at)
689 }
690 #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
691 {
692 None
693 }
694 }
695}
696
697impl<Inner, Prev, K, T> IsDisposed for AtKeyed<Inner, Prev, K, T>
698where
699 for<'a> &'a T: IntoIterator,
700 Inner: IsDisposed,
701{
702 fn is_disposed(&self) -> bool {
703 self.inner.is_disposed()
704 }
705}
706
707impl<Inner, Prev, K, T> Notify for AtKeyed<Inner, Prev, K, T>
708where
709 K: Clone + Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
710 KeyedSubfield<Inner, Prev, K, T>: Clone,
711 for<'a> &'a T: IntoIterator,
712 Inner: StoreField<Value = Prev>,
713 Prev: 'static,
714 T: KeyedAccess<K>,
715 T::Value: Sized,
716{
717 fn notify(&self) {
718 let trigger = self.get_trigger(self.path().into_iter().collect());
719 trigger.this.notify();
720 trigger.children.notify();
721 }
722}
723
724impl<Inner, Prev, K, T> Track for AtKeyed<Inner, Prev, K, T>
725where
726 K: Clone + Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
727 KeyedSubfield<Inner, Prev, K, T>: Clone,
728 for<'a> &'a T: IntoIterator,
729 Inner: StoreField<Value = Prev>,
730 Prev: 'static,
731 T: KeyedAccess<K>,
732 T::Value: Sized,
733{
734 fn track(&self) {
735 self.track_field();
736 }
737}
738
739impl<Inner, Prev, K, T> ReadUntracked for AtKeyed<Inner, Prev, K, T>
740where
741 K: Clone + Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
742 KeyedSubfield<Inner, Prev, K, T>: Clone,
743 for<'a> &'a T: IntoIterator,
744 Inner: StoreField<Value = Prev>,
745 Prev: 'static,
746 T: KeyedAccess<K>,
747 T::Value: Sized,
748{
749 type Value = <Self as StoreField>::Reader;
750
751 fn try_read_untracked(&self) -> Option<Self::Value> {
752 self.reader()
753 }
754}
755
756impl<Inner, Prev, K, T> Write for AtKeyed<Inner, Prev, K, T>
757where
758 K: Clone + Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
759 KeyedSubfield<Inner, Prev, K, T>: Clone,
760 for<'a> &'a T: IntoIterator,
761 Inner: StoreField<Value = Prev>,
762 Prev: 'static,
763 T: KeyedAccess<K>,
764 T::Value: Sized + 'static,
765{
766 type Value = T::Value;
767
768 fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
769 self.writer()
770 }
771
772 fn try_write_untracked(
773 &self,
774 ) -> Option<impl DerefMut<Target = Self::Value>> {
775 self.writer().map(|mut writer| {
776 writer.untrack();
777 writer
778 })
779 }
780}
781
782impl<Inner, Prev, K, T> KeyedSubfield<Inner, Prev, K, T>
783where
784 Self: Clone,
785 for<'a> &'a T: IntoIterator,
786 Inner: StoreField<Value = Prev>,
787 Prev: 'static,
788 K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
789{
790 pub fn update_keys(&self) {
792 let inner_path = self.path().into_iter().collect();
793 let keys = self
794 .inner
795 .keys()
796 .expect("updating keys on a store with no keys");
797
798 let latest = self.latest_keys();
803 keys.with_field_keys(
804 inner_path,
805 |keys| ((), keys.update(latest)),
806 || self.latest_keys(),
807 );
808 }
809}
810
811impl<Inner, Prev, K, T> IntoIterator for KeyedSubfield<Inner, Prev, K, T>
812where
813 Self: Clone,
814 for<'a> &'a T: IntoIterator,
815 Inner: Clone + StoreField<Value = Prev> + 'static,
816 Prev: 'static,
817 K: Clone + Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
818 T: KeyedAccess<K> + 'static,
819 T::Value: Sized,
820{
821 type Item = AtKeyed<Inner, Prev, K, T>;
822 type IntoIter = StoreFieldKeyedIter<Inner, Prev, K, T>;
823
824 #[track_caller]
825 fn into_iter(self) -> StoreFieldKeyedIter<Inner, Prev, K, T> {
826 self.update_keys();
828 self.track_field();
829
830 let reader = self.reader();
832
833 let keys = reader
834 .map(|r| {
835 r.into_iter()
836 .map(|item| (self.key_fn)(item))
837 .collect::<VecDeque<_>>()
838 })
839 .unwrap_or_default();
840
841 StoreFieldKeyedIter { inner: self, keys }
843 }
844}
845
846pub struct StoreFieldKeyedIter<Inner, Prev, K, T>
848where
849 for<'a> &'a T: IntoIterator,
850 T: KeyedAccess<K>,
851{
852 inner: KeyedSubfield<Inner, Prev, K, T>,
853 keys: VecDeque<K>,
854}
855
856impl<Inner, Prev, K, T> Iterator for StoreFieldKeyedIter<Inner, Prev, K, T>
857where
858 Inner: StoreField<Value = Prev> + Clone + 'static,
859 T: KeyedAccess<K> + 'static,
860 for<'a> &'a T: IntoIterator,
861{
862 type Item = AtKeyed<Inner, Prev, K, T>;
863
864 fn next(&mut self) -> Option<Self::Item> {
865 self.keys
866 .pop_front()
867 .map(|key| AtKeyed::new(self.inner.clone(), key))
868 }
869}
870
871impl<Inner, Prev, K, T> DoubleEndedIterator
872 for StoreFieldKeyedIter<Inner, Prev, K, T>
873where
874 Inner: StoreField<Value = Prev> + Clone + 'static,
875 T: KeyedAccess<K> + 'static,
876 T::Value: Sized + 'static,
877 for<'a> &'a T: IntoIterator,
878{
879 fn next_back(&mut self) -> Option<Self::Item> {
880 self.keys
881 .pop_back()
882 .map(|key| AtKeyed::new(self.inner.clone(), key))
883 }
884}
885
886#[cfg(test)]
887mod tests {
888 use crate::{self as reactive_stores, tests::tick, AtKeyed, Store};
889 use reactive_graph::{
890 effect::Effect,
891 traits::{Get, GetUntracked, ReadUntracked, Set, Track, Write},
892 };
893 use reactive_stores::Patch;
894 use std::{
895 collections::{BTreeMap, BTreeSet, HashMap},
896 sync::{
897 atomic::{AtomicUsize, Ordering},
898 Arc,
899 },
900 };
901
902 #[derive(Debug, Store, Default, Patch)]
903 struct TodoVec {
904 #[store(key: usize = |todo| todo.id)]
905 todos: Vec<Todo>,
906 }
907 impl TodoVec {
908 fn test_data() -> Self {
909 Self {
910 todos: vec![
911 Todo {
912 id: 10,
913 label: "A".to_string(),
914 },
915 Todo {
916 id: 11,
917 label: "B".to_string(),
918 },
919 Todo {
920 id: 12,
921 label: "C".to_string(),
922 },
923 ],
924 }
925 }
926 }
927
928 #[derive(Debug, Store, Default)]
929 struct TodoBTreeMap {
930 #[store(key: usize = |(key, _)| *key)]
931 todos: BTreeMap<usize, Todo>,
932 }
933 impl TodoBTreeMap {
934 fn test_data() -> Self {
935 Self {
936 todos: [
937 Todo {
938 id: 10,
939 label: "A".to_string(),
940 },
941 Todo {
942 id: 11,
943 label: "B".to_string(),
944 },
945 Todo {
946 id: 12,
947 label: "C".to_string(),
948 },
949 ]
950 .into_iter()
951 .map(|todo| (todo.id, todo))
952 .collect(),
953 }
954 }
955 }
956
957 #[derive(Debug, Store, Default)]
958 struct TodoHashMap {
959 #[store(key: String = |(key, _)| key.clone())]
960 todos: HashMap<String, Todo>,
961 }
962 impl TodoHashMap {
963 fn test_data() -> Self {
964 Self {
965 todos: [
966 Todo {
967 id: 10,
968 label: "A".to_string(),
969 },
970 Todo {
971 id: 11,
972 label: "B".to_string(),
973 },
974 Todo {
975 id: 12,
976 label: "C".to_string(),
977 },
978 ]
979 .into_iter()
980 .map(|todo| (todo.label.clone(), todo))
981 .collect(),
982 }
983 }
984 }
985
986 #[derive(
987 Debug, Store, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Patch,
988 )]
989 struct Todo {
990 id: usize,
991 label: String,
992 }
993
994 impl Todo {
995 pub fn new(id: usize, label: impl ToString) -> Self {
996 Self {
997 id,
998 label: label.to_string(),
999 }
1000 }
1001 }
1002
1003 #[tokio::test]
1004 async fn keyed_fields_can_be_moved() {
1005 _ = any_spawner::Executor::init_tokio();
1006
1007 let store = Store::new(TodoVec::test_data());
1008 assert_eq!(store.read_untracked().todos.len(), 3);
1009
1010 let a_count = Arc::new(AtomicUsize::new(0));
1012 let b_count = Arc::new(AtomicUsize::new(0));
1013 let c_count = Arc::new(AtomicUsize::new(0));
1014
1015 let a = AtKeyed::new(store.todos(), 10);
1016 let b = AtKeyed::new(store.todos(), 11);
1017 let c = AtKeyed::new(store.todos(), 12);
1018
1019 Effect::new_sync({
1020 let a_count = Arc::clone(&a_count);
1021 move || {
1022 a.track();
1023 a_count.fetch_add(1, Ordering::Relaxed);
1024 }
1025 });
1026 Effect::new_sync({
1027 let b_count = Arc::clone(&b_count);
1028 move || {
1029 b.track();
1030 b_count.fetch_add(1, Ordering::Relaxed);
1031 }
1032 });
1033 Effect::new_sync({
1034 let c_count = Arc::clone(&c_count);
1035 move || {
1036 c.track();
1037 c_count.fetch_add(1, Ordering::Relaxed);
1038 }
1039 });
1040
1041 tick().await;
1042 assert_eq!(a_count.load(Ordering::Relaxed), 1);
1043 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1044 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1045
1046 *a.label().write() = "Foo".into();
1048 tick().await;
1049 assert_eq!(a_count.load(Ordering::Relaxed), 2);
1050 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1051 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1052
1053 store.todos().write().swap(0, 2);
1055 let after = store.todos().get_untracked();
1056 assert_eq!(
1057 after,
1058 vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(10, "Foo")]
1059 );
1060
1061 tick().await;
1062 assert_eq!(a_count.load(Ordering::Relaxed), 3);
1063 assert_eq!(b_count.load(Ordering::Relaxed), 2);
1064 assert_eq!(c_count.load(Ordering::Relaxed), 2);
1065
1066 a.label().set("Bar".into());
1068 let after = store.todos().get_untracked();
1069 assert_eq!(
1070 after,
1071 vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(10, "Bar")]
1072 );
1073 tick().await;
1074 assert_eq!(a_count.load(Ordering::Relaxed), 4);
1075 assert_eq!(b_count.load(Ordering::Relaxed), 2);
1076 assert_eq!(c_count.load(Ordering::Relaxed), 2);
1077
1078 store.todos().write().pop();
1080 store.todos().write().push(Todo::new(13, "New"));
1081 let after = store.todos().get_untracked();
1082 assert_eq!(
1083 after,
1084 vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(13, "New")]
1085 );
1086 tick().await;
1087 assert_eq!(a_count.load(Ordering::Relaxed), 5);
1088 assert_eq!(b_count.load(Ordering::Relaxed), 3);
1089 assert_eq!(c_count.load(Ordering::Relaxed), 3);
1090 }
1091
1092 #[tokio::test]
1093 async fn untracked_write_on_keyed_subfield_shouldnt_notify() {
1094 _ = any_spawner::Executor::init_tokio();
1095
1096 let store = Store::new(TodoVec::test_data());
1097 assert_eq!(store.read_untracked().todos.len(), 3);
1098
1099 let todos_count = Arc::new(AtomicUsize::new(0));
1101 Effect::new_sync({
1102 let todos_count = Arc::clone(&todos_count);
1103 move || {
1104 store.todos().track();
1105 todos_count.fetch_add(1, Ordering::Relaxed);
1106 }
1107 });
1108
1109 tick().await;
1110 assert_eq!(todos_count.load(Ordering::Relaxed), 1);
1111
1112 store.todos().write().push(Todo {
1114 id: 13,
1115 label: "D".into(),
1116 });
1117 tick().await;
1118 assert_eq!(todos_count.load(Ordering::Relaxed), 2);
1119
1120 store.todos().write_untracked().push(Todo {
1122 id: 14,
1123 label: "E".into(),
1124 });
1125 tick().await;
1126 assert_eq!(todos_count.load(Ordering::Relaxed), 2);
1127 }
1128
1129 #[tokio::test]
1130 async fn btree_keyed_fields_can_be_moved() {
1131 _ = any_spawner::Executor::init_tokio();
1132
1133 let store = Store::new(TodoBTreeMap::test_data());
1134 assert_eq!(store.read_untracked().todos.len(), 3);
1135
1136 let a_count = Arc::new(AtomicUsize::new(0));
1138 let b_count = Arc::new(AtomicUsize::new(0));
1139 let c_count = Arc::new(AtomicUsize::new(0));
1140
1141 let a = AtKeyed::new(store.todos(), 10);
1142 let b = AtKeyed::new(store.todos(), 11);
1143 let c = AtKeyed::new(store.todos(), 12);
1144
1145 Effect::new_sync({
1146 let a_count = Arc::clone(&a_count);
1147 move || {
1148 a.track();
1149 a_count.fetch_add(1, Ordering::Relaxed);
1150 }
1151 });
1152 Effect::new_sync({
1153 let b_count = Arc::clone(&b_count);
1154 move || {
1155 b.track();
1156 b_count.fetch_add(1, Ordering::Relaxed);
1157 }
1158 });
1159 Effect::new_sync({
1160 let c_count = Arc::clone(&c_count);
1161 move || {
1162 c.track();
1163 c_count.fetch_add(1, Ordering::Relaxed);
1164 }
1165 });
1166
1167 tick().await;
1168 assert_eq!(a_count.load(Ordering::Relaxed), 1);
1169 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1170 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1171
1172 *a.label().write() = "Foo".into();
1174 tick().await;
1175 assert_eq!(a_count.load(Ordering::Relaxed), 2);
1176 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1177 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1178 let after = store.todos().get_untracked();
1179 assert_eq!(
1180 after.values().cloned().collect::<Vec<_>>(),
1181 vec![Todo::new(10, "Foo"), Todo::new(11, "B"), Todo::new(12, "C"),]
1182 );
1183
1184 a.label().set("Bar".into());
1185 let after = store.todos().get_untracked();
1186 assert_eq!(
1187 after.values().cloned().collect::<Vec<_>>(),
1188 vec![Todo::new(10, "Bar"), Todo::new(11, "B"), Todo::new(12, "C"),]
1189 );
1190 tick().await;
1191 assert_eq!(a_count.load(Ordering::Relaxed), 3);
1192 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1193 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1194
1195 store.todos().write().remove(&12);
1197 store.todos().write().insert(13, Todo::new(13, "New"));
1198 let after = store.todos().get_untracked();
1199 assert_eq!(
1200 after.values().cloned().collect::<Vec<_>>(),
1201 vec![
1202 Todo::new(10, "Bar"),
1203 Todo::new(11, "B"),
1204 Todo::new(13, "New")
1205 ]
1206 );
1207 tick().await;
1208 assert_eq!(a_count.load(Ordering::Relaxed), 4);
1209 assert_eq!(b_count.load(Ordering::Relaxed), 2);
1210 assert_eq!(c_count.load(Ordering::Relaxed), 2);
1211
1212 assert_eq!(
1213 after.keys().copied().collect::<BTreeSet<usize>>(),
1214 BTreeSet::from([10, 11, 13])
1215 );
1216
1217 let at_existing_key = AtKeyed::new(store.todos(), 13);
1218 let existing = at_existing_key.try_get();
1219 assert!(existing.is_some());
1220 assert_eq!(existing, Some(Todo::new(13, "New")));
1221
1222 let at_faulty_key = AtKeyed::new(store.todos(), 999);
1223 let missing = at_faulty_key.try_get();
1224 assert!(missing.is_none(), "faulty key should return none.")
1225 }
1226
1227 #[tokio::test]
1228 async fn hashmap_keyed_fields_can_be_moved() {
1229 _ = any_spawner::Executor::init_tokio();
1230
1231 let store = Store::new(TodoHashMap::test_data());
1232 assert_eq!(store.read_untracked().todos.len(), 3);
1233
1234 let a_count = Arc::new(AtomicUsize::new(0));
1236 let b_count = Arc::new(AtomicUsize::new(0));
1237 let c_count = Arc::new(AtomicUsize::new(0));
1238
1239 let a = AtKeyed::new(store.todos(), "A".to_string());
1240 let b = AtKeyed::new(store.todos(), "B".to_string());
1241 let c = AtKeyed::new(store.todos(), "C".to_string());
1242
1243 Effect::new_sync({
1244 let a_count = Arc::clone(&a_count);
1245 let a = a.clone();
1246 move || {
1247 a.track();
1248 a_count.fetch_add(1, Ordering::Relaxed);
1249 }
1250 });
1251 Effect::new_sync({
1252 let b_count = Arc::clone(&b_count);
1253 move || {
1254 b.track();
1255 b_count.fetch_add(1, Ordering::Relaxed);
1256 }
1257 });
1258 Effect::new_sync({
1259 let c_count = Arc::clone(&c_count);
1260 move || {
1261 c.track();
1262 c_count.fetch_add(1, Ordering::Relaxed);
1263 }
1264 });
1265
1266 tick().await;
1267 assert_eq!(a_count.load(Ordering::Relaxed), 1);
1268 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1269 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1270
1271 *a.clone().label().write() = "Foo".to_string();
1273 tick().await;
1274 assert_eq!(a_count.load(Ordering::Relaxed), 2);
1275 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1276 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1277 let after = store.todos().get_untracked();
1278 assert_eq!(
1279 after.values().cloned().collect::<BTreeSet<_>>(),
1280 BTreeSet::from([
1281 Todo::new(10, "Foo"),
1282 Todo::new(11, "B"),
1283 Todo::new(12, "C"),
1284 ])
1285 );
1286
1287 a.clone().label().set("Bar".into());
1288 let after = store.todos().get_untracked();
1289 assert_eq!(
1290 after.values().cloned().collect::<BTreeSet<_>>(),
1291 BTreeSet::from([
1292 Todo::new(10, "Bar"),
1293 Todo::new(11, "B"),
1294 Todo::new(12, "C")
1295 ]),
1296 );
1297 tick().await;
1298 assert_eq!(a_count.load(Ordering::Relaxed), 3);
1299 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1300 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1301
1302 store.todos().write().remove(&"C".to_string());
1304 store
1305 .todos()
1306 .write()
1307 .insert("New".to_string(), Todo::new(13, "New"));
1308 let after = store.todos().get_untracked();
1309 assert_eq!(
1310 after.values().cloned().collect::<BTreeSet<_>>(),
1311 BTreeSet::from([
1312 Todo::new(10, "Bar"),
1313 Todo::new(11, "B"),
1314 Todo::new(13, "New"),
1315 ])
1316 );
1317 tick().await;
1318 assert_eq!(a_count.load(Ordering::Relaxed), 4);
1319 assert_eq!(b_count.load(Ordering::Relaxed), 2);
1320 assert_eq!(c_count.load(Ordering::Relaxed), 2);
1321
1322 assert_eq!(
1323 after.keys().cloned().collect::<BTreeSet<String>>(),
1324 BTreeSet::from([
1325 "A".to_string(),
1326 "B".to_string(),
1327 "New".to_string()
1328 ])
1329 );
1330
1331 let at_existing_key = AtKeyed::new(store.todos(), "New".to_string());
1332 let existing = at_existing_key.try_get();
1333 assert!(existing.is_some());
1334 assert_eq!(existing, Some(Todo::new(13, "New")));
1335
1336 let at_faulty_key = AtKeyed::new(store.todos(), "faulty".to_string());
1337 let missing = at_faulty_key.try_get();
1338 assert!(missing.is_none(), "faulty key should return none.")
1339 }
1340
1341 #[test]
1342 fn non_usize_keys_work_for_vec() {
1343 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
1344 struct MyIdType(u32);
1345
1346 #[derive(Debug, Store)]
1347 struct Item {
1348 id: MyIdType,
1349 _value: String,
1350 }
1351
1352 #[derive(Debug, Store)]
1353 struct MyStore {
1354 #[store(key: MyIdType = |item| item.id.clone())]
1355 items: Vec<Item>,
1356 }
1357
1358 let store = Store::new(MyStore { items: Vec::new() });
1359
1360 let _fields = store.items().into_iter();
1361 }
1362
1363 #[tokio::test]
1364 async fn patching_keyed_field_only_notifies_changed_keys() {
1365 _ = any_spawner::Executor::init_tokio();
1366
1367 let store = Store::new(TodoVec::test_data());
1368 assert_eq!(store.read_untracked().todos.len(), 3);
1369
1370 let whole_count = Arc::new(AtomicUsize::new(0));
1372 let a_count = Arc::new(AtomicUsize::new(0));
1373 let b_count = Arc::new(AtomicUsize::new(0));
1374 let c_count = Arc::new(AtomicUsize::new(0));
1375
1376 let whole = store.todos();
1377 let a = AtKeyed::new(store.todos(), 10);
1378 let b = AtKeyed::new(store.todos(), 11);
1379 let c = AtKeyed::new(store.todos(), 12);
1380
1381 Effect::new_sync({
1382 let whole_count = Arc::clone(&whole_count);
1383 move || {
1384 whole.track();
1385 whole_count.fetch_add(1, Ordering::Relaxed);
1386 }
1387 });
1388 Effect::new_sync({
1389 let a_count = Arc::clone(&a_count);
1390 move || {
1391 a.track();
1392 a_count.fetch_add(1, Ordering::Relaxed);
1393 }
1394 });
1395 Effect::new_sync({
1396 let b_count = Arc::clone(&b_count);
1397 move || {
1398 b.track();
1399 b_count.fetch_add(1, Ordering::Relaxed);
1400 }
1401 });
1402 Effect::new_sync({
1403 let c_count = Arc::clone(&c_count);
1404 move || {
1405 c.track();
1406 c_count.fetch_add(1, Ordering::Relaxed);
1407 }
1408 });
1409
1410 tick().await;
1411 assert_eq!(whole_count.load(Ordering::Relaxed), 1);
1412 assert_eq!(a_count.load(Ordering::Relaxed), 1);
1413 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1414 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1415
1416 let mut new_data = store.todos().get_untracked();
1418 new_data.swap(0, 2);
1419 store.todos().patch(new_data.clone());
1420 let after = store.todos().get_untracked();
1421 assert_eq!(
1422 after,
1423 vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(10, "A")]
1424 );
1425
1426 tick().await;
1427 assert_eq!(whole_count.load(Ordering::Relaxed), 2);
1428 assert_eq!(a_count.load(Ordering::Relaxed), 1);
1429 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1430 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1431
1432 a.label().set("Bar".into());
1434 let after = store.todos().get_untracked();
1435 assert_eq!(
1436 after,
1437 vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(10, "Bar")]
1438 );
1439 tick().await;
1440 assert_eq!(whole_count.load(Ordering::Relaxed), 3);
1441 assert_eq!(a_count.load(Ordering::Relaxed), 2);
1442 assert_eq!(b_count.load(Ordering::Relaxed), 1);
1443 assert_eq!(c_count.load(Ordering::Relaxed), 1);
1444
1445 store.todos().write().pop();
1447 store.todos().write().push(Todo::new(13, "New"));
1448 let after = store.todos().get_untracked();
1449 assert_eq!(
1450 after,
1451 vec![Todo::new(12, "C"), Todo::new(11, "B"), Todo::new(13, "New")]
1452 );
1453 tick().await;
1454 assert_eq!(whole_count.load(Ordering::Relaxed), 4);
1455 assert_eq!(a_count.load(Ordering::Relaxed), 3);
1456 assert_eq!(b_count.load(Ordering::Relaxed), 2);
1457 assert_eq!(c_count.load(Ordering::Relaxed), 2);
1458 }
1459}