reactive_stores/
field.rs

1use crate::{
2    arc_field::{StoreFieldReader, StoreFieldWriter},
3    path::{StorePath, StorePathSegment},
4    ArcField, ArcStore, AtIndex, AtKeyed, DerefedField, KeyMap, KeyedSubfield,
5    Store, StoreField, StoreFieldTrigger, Subfield,
6};
7use reactive_graph::{
8    owner::{ArenaItem, Storage, SyncStorage},
9    traits::{
10        DefinedAt, IsDisposed, Notify, ReadUntracked, Track, UntrackableGuard,
11        Write,
12    },
13};
14use std::{
15    fmt::Debug,
16    hash::Hash,
17    ops::{Deref, DerefMut, IndexMut},
18    panic::Location,
19};
20
21/// Wraps access to a single field of type `T`.
22///
23/// This can be used to erase the chain of field-accessors, to make it easier to pass this into
24/// another component or function without needing to specify the full type signature.
25pub struct Field<T, S = SyncStorage>
26where
27    T: 'static,
28{
29    #[cfg(any(debug_assertions, leptos_debuginfo))]
30    defined_at: &'static Location<'static>,
31    inner: ArenaItem<ArcField<T>, S>,
32}
33
34impl<T, S> Debug for Field<T, S>
35where
36    T: 'static,
37    S: Debug,
38{
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        let mut f = f.debug_struct("Field");
41        #[cfg(any(debug_assertions, leptos_debuginfo))]
42        let f = f.field("defined_at", &self.defined_at);
43        f.field("inner", &self.inner).finish()
44    }
45}
46
47impl<T, S> StoreField for Field<T, S>
48where
49    S: Storage<ArcField<T>>,
50{
51    type Value = T;
52    type Reader = StoreFieldReader<T>;
53    type Writer = StoreFieldWriter<T>;
54
55    fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
56        self.inner
57            .try_get_value()
58            .map(|inner| inner.get_trigger(path))
59            .unwrap_or_default()
60    }
61
62    fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
63        self.inner
64            .try_get_value()
65            .map(|inner| inner.path().into_iter().collect::<Vec<_>>())
66            .unwrap_or_default()
67    }
68
69    fn reader(&self) -> Option<Self::Reader> {
70        self.inner.try_get_value().and_then(|inner| inner.reader())
71    }
72
73    fn writer(&self) -> Option<Self::Writer> {
74        self.inner.try_get_value().and_then(|inner| inner.writer())
75    }
76
77    fn keys(&self) -> Option<KeyMap> {
78        self.inner.try_get_value().and_then(|n| n.keys())
79    }
80}
81
82impl<T, S> From<Store<T, S>> for Field<T, S>
83where
84    T: 'static,
85    S: Storage<ArcStore<T>> + Storage<ArcField<T>>,
86{
87    #[track_caller]
88    fn from(value: Store<T, S>) -> Self {
89        Field {
90            #[cfg(any(debug_assertions, leptos_debuginfo))]
91            defined_at: Location::caller(),
92            inner: ArenaItem::new_with_storage(value.into()),
93        }
94    }
95}
96
97impl<T, S> From<ArcField<T>> for Field<T, S>
98where
99    T: 'static,
100    S: Storage<ArcField<T>>,
101{
102    #[track_caller]
103    fn from(value: ArcField<T>) -> Self {
104        Field {
105            #[cfg(any(debug_assertions, leptos_debuginfo))]
106            defined_at: Location::caller(),
107            inner: ArenaItem::new_with_storage(value),
108        }
109    }
110}
111
112impl<T, S> From<ArcStore<T>> for Field<T, S>
113where
114    T: Send + Sync + 'static,
115    S: Storage<ArcStore<T>> + Storage<ArcField<T>>,
116{
117    #[track_caller]
118    fn from(value: ArcStore<T>) -> Self {
119        Field {
120            #[cfg(any(debug_assertions, leptos_debuginfo))]
121            defined_at: Location::caller(),
122            inner: ArenaItem::new_with_storage(value.into()),
123        }
124    }
125}
126
127impl<Inner, Prev, T, S> From<Subfield<Inner, Prev, T>> for Field<T, S>
128where
129    T: Send + Sync,
130    S: Storage<ArcField<T>>,
131    Subfield<Inner, Prev, T>: Clone,
132    Inner: StoreField<Value = Prev> + Send + Sync + 'static,
133    Prev: 'static,
134{
135    #[track_caller]
136    fn from(value: Subfield<Inner, Prev, T>) -> Self {
137        Field {
138            #[cfg(any(debug_assertions, leptos_debuginfo))]
139            defined_at: Location::caller(),
140            inner: ArenaItem::new_with_storage(value.into()),
141        }
142    }
143}
144
145impl<Inner, T> From<DerefedField<Inner>> for Field<T>
146where
147    Inner: Clone + StoreField + Send + Sync + 'static,
148    Inner::Value: Deref<Target = T> + DerefMut,
149    T: Sized + 'static,
150{
151    #[track_caller]
152    fn from(value: DerefedField<Inner>) -> Self {
153        Field {
154            #[cfg(any(debug_assertions, leptos_debuginfo))]
155            defined_at: Location::caller(),
156            inner: ArenaItem::new_with_storage(value.into()),
157        }
158    }
159}
160
161impl<Inner, Prev, S> From<AtIndex<Inner, Prev>> for Field<Prev::Output, S>
162where
163    AtIndex<Inner, Prev>: Clone,
164    S: Storage<ArcField<Prev::Output>>,
165    Inner: StoreField<Value = Prev> + Send + Sync + 'static,
166    Prev: IndexMut<usize> + Send + Sync + 'static,
167    Prev::Output: Sized + Send + Sync,
168{
169    #[track_caller]
170    fn from(value: AtIndex<Inner, Prev>) -> Self {
171        Field {
172            #[cfg(any(debug_assertions, leptos_debuginfo))]
173            defined_at: Location::caller(),
174            inner: ArenaItem::new_with_storage(value.into()),
175        }
176    }
177}
178
179impl<Inner, Prev, K, T, S> From<AtKeyed<Inner, Prev, K, T>>
180    for Field<T::Output, S>
181where
182    S: Storage<ArcField<T::Output>>,
183    AtKeyed<Inner, Prev, K, T>: Clone,
184    K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
185    KeyedSubfield<Inner, Prev, K, T>: Clone,
186    for<'a> &'a T: IntoIterator,
187    Inner: StoreField<Value = Prev> + Send + Sync + 'static,
188    Prev: 'static,
189    T: IndexMut<usize> + 'static,
190    T::Output: Sized,
191{
192    #[track_caller]
193    fn from(value: AtKeyed<Inner, Prev, K, T>) -> Self {
194        Field {
195            #[cfg(any(debug_assertions, leptos_debuginfo))]
196            defined_at: Location::caller(),
197            inner: ArenaItem::new_with_storage(value.into()),
198        }
199    }
200}
201
202impl<T, S> Clone for Field<T, S> {
203    fn clone(&self) -> Self {
204        *self
205    }
206}
207
208impl<T, S> Copy for Field<T, S> {}
209
210impl<T, S> DefinedAt for Field<T, S> {
211    fn defined_at(&self) -> Option<&'static Location<'static>> {
212        #[cfg(any(debug_assertions, leptos_debuginfo))]
213        {
214            Some(self.defined_at)
215        }
216        #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
217        {
218            None
219        }
220    }
221}
222
223impl<T, S> Notify for Field<T, S>
224where
225    S: Storage<ArcField<T>>,
226{
227    fn notify(&self) {
228        if let Some(inner) = self.inner.try_get_value() {
229            inner.notify();
230        }
231    }
232}
233
234impl<T, S> Track for Field<T, S>
235where
236    S: Storage<ArcField<T>>,
237{
238    fn track(&self) {
239        if let Some(inner) = self.inner.try_get_value() {
240            inner.track();
241        }
242    }
243}
244
245impl<T, S> ReadUntracked for Field<T, S>
246where
247    S: Storage<ArcField<T>>,
248{
249    type Value = StoreFieldReader<T>;
250
251    fn try_read_untracked(&self) -> Option<Self::Value> {
252        self.inner
253            .try_get_value()
254            .and_then(|inner| inner.try_read_untracked())
255    }
256}
257
258impl<T> Write for Field<T> {
259    type Value = T;
260
261    fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
262        self.inner.try_get_value().and_then(|inner| (inner.write)())
263    }
264
265    fn try_write_untracked(
266        &self,
267    ) -> Option<impl DerefMut<Target = Self::Value>> {
268        self.inner.try_get_value().and_then(|inner| {
269            let mut guard = (inner.write)()?;
270            guard.untrack();
271            Some(guard)
272        })
273    }
274}
275
276impl<T, S> IsDisposed for Field<T, S> {
277    fn is_disposed(&self) -> bool {
278        self.inner.is_disposed()
279    }
280}