Skip to main content

reactive_stores/
field.rs

1use crate::{
2    arc_field::{StoreFieldReader, StoreFieldWriter},
3    path::{StorePath, StorePathSegment},
4    ArcField, ArcStore, AtIndex, AtKeyed, DerefedField, KeyMap, KeyedAccess,
5    KeyedSubfield, 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 get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
63        self.inner
64            .try_get_value()
65            .map(|inner| inner.get_trigger_unkeyed(path))
66            .unwrap_or_default()
67    }
68
69    fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
70        self.inner
71            .try_get_value()
72            .map(|inner| inner.path().into_iter().collect::<Vec<_>>())
73            .unwrap_or_default()
74    }
75
76    fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
77        self.inner
78            .try_get_value()
79            .map(|inner| inner.path_unkeyed().into_iter().collect::<Vec<_>>())
80            .unwrap_or_default()
81    }
82
83    fn reader(&self) -> Option<Self::Reader> {
84        self.inner.try_get_value().and_then(|inner| inner.reader())
85    }
86
87    fn writer(&self) -> Option<Self::Writer> {
88        self.inner.try_get_value().and_then(|inner| inner.writer())
89    }
90
91    fn keys(&self) -> Option<KeyMap> {
92        self.inner.try_get_value().and_then(|n| n.keys())
93    }
94}
95
96impl<T, S> From<Store<T, S>> for Field<T, S>
97where
98    T: 'static,
99    S: Storage<ArcStore<T>> + Storage<ArcField<T>>,
100{
101    #[track_caller]
102    fn from(value: Store<T, S>) -> Self {
103        Field {
104            #[cfg(any(debug_assertions, leptos_debuginfo))]
105            defined_at: Location::caller(),
106            inner: ArenaItem::new_with_storage(value.into()),
107        }
108    }
109}
110
111impl<T, S> From<ArcField<T>> for Field<T, S>
112where
113    T: 'static,
114    S: Storage<ArcField<T>>,
115{
116    #[track_caller]
117    fn from(value: ArcField<T>) -> Self {
118        Field {
119            #[cfg(any(debug_assertions, leptos_debuginfo))]
120            defined_at: Location::caller(),
121            inner: ArenaItem::new_with_storage(value),
122        }
123    }
124}
125
126impl<T, S> From<ArcStore<T>> for Field<T, S>
127where
128    T: Send + Sync + 'static,
129    S: Storage<ArcStore<T>> + Storage<ArcField<T>>,
130{
131    #[track_caller]
132    fn from(value: ArcStore<T>) -> Self {
133        Field {
134            #[cfg(any(debug_assertions, leptos_debuginfo))]
135            defined_at: Location::caller(),
136            inner: ArenaItem::new_with_storage(value.into()),
137        }
138    }
139}
140
141impl<Inner, Prev, T, S> From<Subfield<Inner, Prev, T>> for Field<T, S>
142where
143    T: Send + Sync,
144    S: Storage<ArcField<T>>,
145    Subfield<Inner, Prev, T>: Clone,
146    Inner: StoreField<Value = Prev> + Send + Sync + 'static,
147    Prev: 'static,
148{
149    #[track_caller]
150    fn from(value: Subfield<Inner, Prev, T>) -> Self {
151        Field {
152            #[cfg(any(debug_assertions, leptos_debuginfo))]
153            defined_at: Location::caller(),
154            inner: ArenaItem::new_with_storage(value.into()),
155        }
156    }
157}
158
159impl<Inner, T> From<DerefedField<Inner>> for Field<T>
160where
161    Inner: Clone + StoreField + Send + Sync + 'static,
162    Inner::Value: Deref<Target = T> + DerefMut,
163    T: Sized + 'static,
164{
165    #[track_caller]
166    fn from(value: DerefedField<Inner>) -> Self {
167        Field {
168            #[cfg(any(debug_assertions, leptos_debuginfo))]
169            defined_at: Location::caller(),
170            inner: ArenaItem::new_with_storage(value.into()),
171        }
172    }
173}
174
175impl<Inner, Prev, S> From<AtIndex<Inner, Prev>> for Field<Prev::Output, S>
176where
177    AtIndex<Inner, Prev>: Clone,
178    S: Storage<ArcField<Prev::Output>>,
179    Inner: StoreField<Value = Prev> + Send + Sync + 'static,
180    Prev: IndexMut<usize> + Send + Sync + 'static,
181    Prev::Output: Sized + Send + Sync,
182{
183    #[track_caller]
184    fn from(value: AtIndex<Inner, Prev>) -> Self {
185        Field {
186            #[cfg(any(debug_assertions, leptos_debuginfo))]
187            defined_at: Location::caller(),
188            inner: ArenaItem::new_with_storage(value.into()),
189        }
190    }
191}
192
193impl<Inner, Prev, K, T, S> From<AtKeyed<Inner, Prev, K, T>>
194    for Field<T::Value, S>
195where
196    S: Storage<ArcField<T::Value>>,
197    AtKeyed<Inner, Prev, K, T>: Clone,
198    K: Clone + Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
199    KeyedSubfield<Inner, Prev, K, T>: Clone,
200    for<'a> &'a T: IntoIterator,
201    Inner: StoreField<Value = Prev> + Send + Sync + 'static,
202    Prev: 'static,
203    T: KeyedAccess<K> + 'static,
204    T::Value: Sized,
205{
206    #[track_caller]
207    fn from(value: AtKeyed<Inner, Prev, K, T>) -> Self {
208        Field {
209            #[cfg(any(debug_assertions, leptos_debuginfo))]
210            defined_at: Location::caller(),
211            inner: ArenaItem::new_with_storage(value.into()),
212        }
213    }
214}
215
216impl<T, S> Clone for Field<T, S> {
217    fn clone(&self) -> Self {
218        *self
219    }
220}
221
222impl<T, S> Copy for Field<T, S> {}
223
224impl<T, S> DefinedAt for Field<T, S> {
225    fn defined_at(&self) -> Option<&'static Location<'static>> {
226        #[cfg(any(debug_assertions, leptos_debuginfo))]
227        {
228            Some(self.defined_at)
229        }
230        #[cfg(not(any(debug_assertions, leptos_debuginfo)))]
231        {
232            None
233        }
234    }
235}
236
237impl<T, S> Notify for Field<T, S>
238where
239    S: Storage<ArcField<T>>,
240{
241    fn notify(&self) {
242        if let Some(inner) = self.inner.try_get_value() {
243            inner.notify();
244        }
245    }
246}
247
248impl<T, S> Track for Field<T, S>
249where
250    S: Storage<ArcField<T>>,
251{
252    fn track(&self) {
253        if let Some(inner) = self.inner.try_get_value() {
254            inner.track();
255        }
256    }
257}
258
259impl<T, S> ReadUntracked for Field<T, S>
260where
261    S: Storage<ArcField<T>>,
262{
263    type Value = StoreFieldReader<T>;
264
265    fn try_read_untracked(&self) -> Option<Self::Value> {
266        self.inner
267            .try_get_value()
268            .and_then(|inner| inner.try_read_untracked())
269    }
270}
271
272impl<T> Write for Field<T> {
273    type Value = T;
274
275    fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
276        self.inner.try_get_value().and_then(|inner| (inner.write)())
277    }
278
279    fn try_write_untracked(
280        &self,
281    ) -> Option<impl DerefMut<Target = Self::Value>> {
282        self.inner.try_get_value().and_then(|inner| {
283            let mut guard = (inner.write)()?;
284            guard.untrack();
285            Some(guard)
286        })
287    }
288}
289
290impl<T, S> IsDisposed for Field<T, S> {
291    fn is_disposed(&self) -> bool {
292        self.inner.is_disposed()
293    }
294}