1use crate::{
2 len::Len,
3 path::{StorePath, StorePathSegment},
4 store_field::StoreField,
5 KeyMap, StoreFieldTrigger,
6};
7use reactive_graph::{
8 signal::{
9 guards::{MappedMutArc, WriteGuard},
10 ArcTrigger,
11 },
12 traits::{
13 DefinedAt, IsDisposed, Notify, ReadUntracked, Track, UntrackableGuard,
14 Write,
15 },
16};
17use std::{
18 iter,
19 marker::PhantomData,
20 ops::{DerefMut, IndexMut},
21 panic::Location,
22};
23
24#[derive(Debug)]
26pub struct AtIndex<Inner, Prev> {
27 #[cfg(any(debug_assertions, leptos_debuginfo))]
28 defined_at: &'static Location<'static>,
29 inner: Inner,
30 index: usize,
31 ty: PhantomData<Prev>,
32}
33
34impl<Inner, Prev> Clone for AtIndex<Inner, Prev>
35where
36 Inner: Clone,
37{
38 fn clone(&self) -> Self {
39 Self {
40 #[cfg(any(debug_assertions, leptos_debuginfo))]
41 defined_at: self.defined_at,
42 inner: self.inner.clone(),
43 index: self.index,
44 ty: self.ty,
45 }
46 }
47}
48
49impl<Inner, Prev> Copy for AtIndex<Inner, Prev> where Inner: Copy {}
50
51impl<Inner, Prev> AtIndex<Inner, Prev> {
52 #[track_caller]
54 pub fn new(inner: Inner, index: usize) -> Self {
55 Self {
56 #[cfg(any(debug_assertions, leptos_debuginfo))]
57 defined_at: Location::caller(),
58 inner,
59 index,
60 ty: PhantomData,
61 }
62 }
63}
64
65impl<Inner, Prev> StoreField for AtIndex<Inner, Prev>
66where
67 Inner: StoreField<Value = Prev>,
68 Prev: IndexMut<usize> + 'static,
69 Prev::Output: Sized,
70{
71 type Value = Prev::Output;
72 type Reader = MappedMutArc<Inner::Reader, Prev::Output>;
73 type Writer =
74 MappedMutArc<WriteGuard<ArcTrigger, Inner::Writer>, Prev::Output>;
75
76 fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
77 self.inner
78 .path()
79 .into_iter()
80 .chain(iter::once(self.index.into()))
81 }
82
83 fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
84 self.inner
85 .path_unkeyed()
86 .into_iter()
87 .chain(iter::once(self.index.into()))
88 }
89
90 fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
91 self.inner.get_trigger(path)
92 }
93
94 fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
95 self.inner.get_trigger_unkeyed(path)
96 }
97
98 fn reader(&self) -> Option<Self::Reader> {
99 let inner = self.inner.reader()?;
100 let index = self.index;
101 Some(MappedMutArc::new(
102 inner,
103 move |n| &n[index],
104 move |n| &mut n[index],
105 ))
106 }
107
108 fn writer(&self) -> Option<Self::Writer> {
109 let trigger = self.get_trigger(self.path().into_iter().collect());
110 let inner = WriteGuard::new(trigger.children, self.inner.writer()?);
111 let index = self.index;
112 Some(MappedMutArc::new(
113 inner,
114 move |n| &n[index],
115 move |n| &mut n[index],
116 ))
117 }
118
119 #[inline(always)]
120 fn keys(&self) -> Option<KeyMap> {
121 self.inner.keys()
122 }
123
124 fn track_field(&self) {
125 let mut full_path = self.path().into_iter().collect::<StorePath>();
126 let trigger = self.get_trigger(self.path().into_iter().collect());
127 trigger.this.track();
128 trigger.children.track();
129
130 while !full_path.is_empty() {
135 full_path.pop();
136 let inner = self.get_trigger(full_path.clone());
137 inner.this.track();
138 }
139 }
140}
141
142impl<Inner, Prev> DefinedAt for AtIndex<Inner, Prev>
143where
144 Inner: StoreField<Value = Prev>,
145{
146 fn defined_at(&self) -> Option<&'static Location<'static>> {
147 #[cfg(any(debug_assertions, leptos_debuginfo))]
148 {
149 Some(self.defined_at)
150 }
151 #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
152 {
153 None
154 }
155 }
156}
157
158impl<Inner, Prev> IsDisposed for AtIndex<Inner, Prev>
159where
160 Inner: StoreField<Value = Prev> + IsDisposed,
161{
162 fn is_disposed(&self) -> bool {
163 self.inner.is_disposed()
164 }
165}
166
167impl<Inner, Prev> Notify for AtIndex<Inner, Prev>
168where
169 Inner: StoreField<Value = Prev>,
170 Prev: IndexMut<usize> + 'static,
171 Prev::Output: Sized,
172{
173 fn notify(&self) {
174 let trigger = self.get_trigger(self.path().into_iter().collect());
175 trigger.this.notify();
176 }
177}
178
179impl<Inner, Prev> Track for AtIndex<Inner, Prev>
180where
181 Inner: StoreField<Value = Prev> + Send + Sync + Clone + 'static,
182 Prev: IndexMut<usize> + 'static,
183 Prev::Output: Sized + 'static,
184{
185 fn track(&self) {
186 self.track_field();
187 }
188}
189
190impl<Inner, Prev> ReadUntracked for AtIndex<Inner, Prev>
191where
192 Inner: StoreField<Value = Prev>,
193 Prev: IndexMut<usize> + 'static,
194 Prev::Output: Sized,
195{
196 type Value = <Self as StoreField>::Reader;
197
198 fn try_read_untracked(&self) -> Option<Self::Value> {
199 self.reader()
200 }
201}
202
203impl<Inner, Prev> Write for AtIndex<Inner, Prev>
204where
205 Inner: StoreField<Value = Prev>,
206 Prev: IndexMut<usize> + 'static,
207 Prev::Output: Sized + 'static,
208{
209 type Value = Prev::Output;
210
211 fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
212 self.writer()
213 }
214
215 fn try_write_untracked(
216 &self,
217 ) -> Option<impl DerefMut<Target = Self::Value>> {
218 self.writer().map(|mut writer| {
219 writer.untrack();
220 writer
221 })
222 }
223}
224
225pub trait StoreFieldIterator<Prev>
227where
228 Self: StoreField<Value = Prev>,
229{
230 fn at_unkeyed(self, index: usize) -> AtIndex<Self, Prev>;
232
233 fn iter_unkeyed(self) -> StoreFieldIter<Self, Prev>;
235}
236
237impl<Inner, Prev> StoreFieldIterator<Prev> for Inner
238where
239 Inner: StoreField<Value = Prev> + Clone,
240 Prev::Output: Sized,
241 Prev: IndexMut<usize> + Len,
242{
243 #[track_caller]
244 fn at_unkeyed(self, index: usize) -> AtIndex<Inner, Prev> {
245 AtIndex::new(self.clone(), index)
246 }
247
248 #[track_caller]
249 fn iter_unkeyed(self) -> StoreFieldIter<Inner, Prev> {
250 let trigger = self.get_trigger(self.path().into_iter().collect());
252 trigger.this.track();
253 trigger.children.track();
254
255 let len = self.reader().map(|n| n.len()).unwrap_or(0);
257
258 StoreFieldIter {
260 inner: self,
261 idx: 0,
262 len,
263 prev: PhantomData,
264 }
265 }
266}
267
268pub struct StoreFieldIter<Inner, Prev> {
270 inner: Inner,
271 idx: usize,
272 len: usize,
273 prev: PhantomData<Prev>,
274}
275
276impl<Inner, Prev> Iterator for StoreFieldIter<Inner, Prev>
277where
278 Inner: StoreField<Value = Prev> + Clone + 'static,
279 Prev: IndexMut<usize> + 'static,
280 Prev::Output: Sized + 'static,
281{
282 type Item = AtIndex<Inner, Prev>;
283
284 fn next(&mut self) -> Option<Self::Item> {
285 if self.idx < self.len {
286 let field = AtIndex::new(self.inner.clone(), self.idx);
287 self.idx += 1;
288 Some(field)
289 } else {
290 None
291 }
292 }
293}
294
295impl<Inner, Prev> DoubleEndedIterator for StoreFieldIter<Inner, Prev>
296where
297 Inner: StoreField<Value = Prev> + Clone + 'static,
298 Prev: IndexMut<usize> + 'static,
299 Prev::Output: Sized + 'static,
300{
301 fn next_back(&mut self) -> Option<Self::Item> {
302 if self.len > self.idx {
303 self.len -= 1;
304 let field = AtIndex::new(self.inner.clone(), self.len);
305 Some(field)
306 } else {
307 None
308 }
309 }
310}