reactive_stores/
store_field.rs1use crate::{
2 ArcStore, KeyMap, Store, StoreFieldTrigger,
3 path::{StorePath, StorePathSegment},
4};
5use or_poisoned::OrPoisoned;
6use reactive_graph::{
7 owner::Storage,
8 signal::{
9 ArcTrigger,
10 guards::{Plain, UntrackedWriteGuard, WriteGuard},
11 },
12 traits::{Track, UntrackableGuard},
13};
14use std::{iter, ops::Deref, sync::Arc};
15
16pub trait StoreField: Sized {
18 type Value;
20 type Reader: Deref<Target = Self::Value>;
22 type Writer: UntrackableGuard<Target = Self::Value>;
24
25 #[track_caller]
27 fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger;
28
29 #[track_caller]
35 fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger;
36
37 #[track_caller]
39 fn path(&self) -> impl IntoIterator<Item = StorePathSegment>;
40
41 #[track_caller]
43 fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
44 self.path()
46 }
47
48 #[track_caller]
50 fn track_field(&self) {
51 let path = self.path().into_iter().collect();
52 let trigger = self.get_trigger(path);
53 trigger.this.track();
54 trigger.children.track();
55 }
56
57 #[track_caller]
59 fn reader(&self) -> Option<Self::Reader>;
60
61 #[track_caller]
63 fn writer(&self) -> Option<Self::Writer>;
64
65 #[track_caller]
67 fn keys(&self) -> Option<KeyMap>;
68
69 fn triggers_for_current_path(&self) -> Vec<ArcTrigger> {
71 self.triggers_for_path(self.path().into_iter().collect())
72 }
73
74 fn triggers_for_path(&self, path: StorePath) -> Vec<ArcTrigger> {
76 let trigger = self.get_trigger(path.clone());
77 let mut full_path = path;
78
79 let mut triggers = Vec::with_capacity(full_path.len() + 2);
82 triggers.push(trigger.this.clone());
83 triggers.push(trigger.children.clone());
84 while !full_path.is_empty() {
85 full_path.pop();
86 let inner = self.get_trigger(full_path.clone());
87 triggers.push(inner.children.clone());
88 }
89
90 triggers.reverse();
99
100 triggers
101 }
102
103 fn triggers_for_path_unkeyed(&self, path: StorePath) -> Vec<ArcTrigger> {
105 let trigger = self.get_trigger_unkeyed(path.clone());
108 let mut full_path = path;
109
110 let mut triggers = Vec::with_capacity(full_path.len() + 2);
111 triggers.push(trigger.this.clone());
112 triggers.push(trigger.children.clone());
113 while !full_path.is_empty() {
114 full_path.pop();
115 let inner = self.get_trigger_unkeyed(full_path.clone());
116 triggers.push(inner.children.clone());
117 }
118 triggers.reverse();
119
120 triggers
121 }
122}
123
124impl<T> StoreField for ArcStore<T>
125where
126 T: 'static,
127{
128 type Value = T;
129 type Reader = Plain<T>;
130 type Writer = WriteGuard<ArcTrigger, UntrackedWriteGuard<T>>;
131
132 #[track_caller]
133 fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
134 let triggers = &self.signals;
135
136 triggers.write().or_poisoned().get_or_insert(path)
137 }
138
139 #[track_caller]
140 fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
141 let caller = std::panic::Location::caller();
142 let orig_path = path.clone();
143
144 let mut path = StorePath::with_capacity(orig_path.len());
145 for segment in &orig_path {
146 let parent_is_keyed = self.keys.contains_key(&path);
147
148 if parent_is_keyed {
149 let key = self
150 .keys
151 .get_key_for_index(&(path.clone(), segment.0))
152 .unwrap_or_else(|| {
153 panic!(
154 "could not find key for index {:?} at {}",
155 (path.clone(), segment.0),
156 caller
157 )
158 });
159 path.push(key);
160 } else {
161 path.push(*segment);
162 }
163 }
164 self.get_trigger(path)
165 }
166
167 #[track_caller]
168 fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
169 iter::empty()
170 }
171
172 #[track_caller]
173 fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
174 iter::empty()
175 }
176
177 #[track_caller]
178 fn reader(&self) -> Option<Self::Reader> {
179 Plain::try_new(Arc::clone(&self.value))
180 }
181
182 #[track_caller]
183 fn writer(&self) -> Option<Self::Writer> {
184 let trigger = self.get_trigger(Default::default());
185 let guard = UntrackedWriteGuard::try_new(Arc::clone(&self.value))?;
186 Some(WriteGuard::new(trigger.children, guard))
187 }
188
189 #[track_caller]
190 fn keys(&self) -> Option<KeyMap> {
191 Some(self.keys.clone())
192 }
193}
194
195impl<T, S> StoreField for Store<T, S>
196where
197 T: 'static,
198 S: Storage<ArcStore<T>>,
199{
200 type Value = T;
201 type Reader = Plain<T>;
202 type Writer = WriteGuard<ArcTrigger, UntrackedWriteGuard<T>>;
203
204 #[track_caller]
205 fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
206 self.inner
207 .try_get_value()
208 .map(|n| n.get_trigger(path))
209 .unwrap_or_default()
210 }
211
212 #[track_caller]
213 fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
214 self.inner
215 .try_get_value()
216 .map(|n| n.get_trigger_unkeyed(path))
217 .unwrap_or_default()
218 }
219
220 #[track_caller]
221 fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
222 self.inner
223 .try_get_value()
224 .map(|n| n.path().into_iter().collect::<Vec<_>>())
225 .unwrap_or_default()
226 }
227
228 #[track_caller]
229 fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
230 self.inner
231 .try_get_value()
232 .map(|n| n.path_unkeyed().into_iter().collect::<Vec<_>>())
233 .unwrap_or_default()
234 }
235
236 #[track_caller]
237 fn reader(&self) -> Option<Self::Reader> {
238 self.inner.try_get_value().and_then(|n| n.reader())
239 }
240
241 #[track_caller]
242 fn writer(&self) -> Option<Self::Writer> {
243 self.inner.try_get_value().and_then(|n| n.writer())
244 }
245
246 #[track_caller]
247 fn keys(&self) -> Option<KeyMap> {
248 self.inner.try_get_value().and_then(|inner| inner.keys())
249 }
250}