dioxus_stores/impls/
option.rs

1use std::ops::DerefMut;
2
3use crate::{store::Store, MappedStore};
4use dioxus_signals::{Readable, ReadableExt};
5
6impl<Lens: Readable<Target = Option<T>> + 'static, T: 'static> Store<Option<T>, Lens> {
7    /// Checks if the `Option` is `Some`. This will only track the shallow state of the `Option`. It will
8    /// only cause a re-run if the `Option` could change from `None` to `Some` or vice versa.
9    ///
10    /// # Example
11    /// ```rust, no_run
12    /// use dioxus_stores::*;
13    /// let store = use_store(|| Some(42));
14    /// assert!(store.is_some());
15    /// ```
16    pub fn is_some(&self) -> bool {
17        self.selector().track_shallow();
18        self.selector().peek().is_some()
19    }
20
21    /// Returns true if the option is Some and the closure returns true. This will always track the shallow
22    /// state of the and will track the inner state of the enum if the enum is Some.
23    ///
24    /// # Example
25    /// ```rust, no_run
26    /// use dioxus_stores::*;
27    /// let store = use_store(|| Some(42));
28    /// assert!(store.is_some_and(|v| *v == 42));
29    /// ```
30    pub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
31        self.selector().track_shallow();
32        let value = self.selector().peek();
33        if let Some(v) = &*value {
34            self.selector().track();
35            f(v)
36        } else {
37            false
38        }
39    }
40
41    /// Checks if the `Option` is `None`. This will only track the shallow state of the `Option`. It will
42    /// only cause a re-run if the `Option` could change from `Some` to `None` or vice versa.
43    ///
44    /// # Example
45    /// ```rust, no_run
46    /// use dioxus_stores::*;
47    /// let store = use_store(|| None::<i32>);
48    /// assert!(store.is_none());
49    /// ```
50    pub fn is_none(&self) -> bool {
51        self.selector().track_shallow();
52        self.selector().peek().is_none()
53    }
54
55    /// Returns true if the option is None or the closure returns true. This will always track the shallow
56    /// state of the and will track the inner state of the enum if the enum is Some.
57    ///
58    /// # Example
59    /// ```rust, no_run
60    /// use dioxus_stores::*;
61    /// let store = use_store(|| Some(42));
62    /// assert!(store.is_none_or(|v| *v == 42));
63    /// ```
64    pub fn is_none_or(&self, f: impl FnOnce(&T) -> bool) -> bool {
65        self.selector().track_shallow();
66        let value = self.selector().peek();
67        if let Some(v) = &*value {
68            self.selector().track();
69            f(v)
70        } else {
71            true
72        }
73    }
74
75    /// Transpose the `Store<Option<T>>` into a `Option<Store<T>>`. This will only track the shallow state of the `Option`. It will
76    /// only cause a re-run if the `Option` could change from `None` to `Some` or vice versa.
77    ///
78    /// # Example
79    /// ```rust, no_run
80    /// use dioxus_stores::*;
81    /// let store = use_store(|| Some(42));
82    /// let transposed = store.transpose();
83    /// match transposed {
84    ///     Some(inner_store) => assert_eq!(inner_store(), 42),
85    ///     None => panic!("Expected Some"),
86    /// }
87    /// ```
88    pub fn transpose(self) -> Option<MappedStore<T, Lens>> {
89        self.is_some().then(move || {
90            let map: fn(&Option<T>) -> &T = |value| {
91                value.as_ref().unwrap_or_else(|| {
92                    panic!("Tried to access `Some` on an Option value");
93                })
94            };
95            let map_mut: fn(&mut Option<T>) -> &mut T = |value| {
96                value.as_mut().unwrap_or_else(|| {
97                    panic!("Tried to access `Some` on an Option value");
98                })
99            };
100            self.into_selector().child(0, map, map_mut).into()
101        })
102    }
103
104    /// Unwraps the `Option` and returns a `Store<T>`. This will only track the shallow state of the `Option`. It will
105    /// only cause a re-run if the `Option` could change from `None` to `Some` or vice versa.
106    ///
107    /// # Example
108    /// ```rust, no_run
109    /// use dioxus_stores::*;
110    /// let store = use_store(|| Some(42));
111    /// let unwrapped = store.unwrap();
112    /// assert_eq!(unwrapped(), 42);
113    /// ```
114    pub fn unwrap(self) -> MappedStore<T, Lens> {
115        self.transpose().unwrap()
116    }
117
118    /// Expects the `Option` to be `Some` and returns a `Store<T>`. If the value is `None`, this will panic with `msg`. This will
119    /// only track the shallow state of the `Option`. It will only cause a re-run if the `Option` could change from `None`
120    /// to `Some` or vice versa.
121    ///
122    /// # Example
123    /// ```rust, no_run
124    /// use dioxus_stores::*;
125    /// let store = use_store(|| Some(42));
126    /// let unwrapped = store.expect("the answer to life the universe and everything");
127    /// assert_eq!(unwrapped(), 42);
128    /// ```
129    pub fn expect(self, msg: &str) -> MappedStore<T, Lens> {
130        self.transpose().expect(msg)
131    }
132
133    /// Returns a slice of the contained value, or an empty slice. This will not subscribe to any part of the store.
134    ///
135    /// # Example
136    /// ```rust, no_run
137    /// use dioxus::prelude::*;
138    /// use dioxus_stores::*;
139    /// let store = use_store(|| Some(42));
140    /// let slice = store.as_slice();
141    /// assert_eq!(&*slice.read(), [42]);
142    /// ```
143    pub fn as_slice(self) -> MappedStore<[T], Lens> {
144        let map: fn(&Option<T>) -> &[T] = |value| value.as_slice();
145        let map_mut: fn(&mut Option<T>) -> &mut [T] = |value| value.as_mut_slice();
146        self.into_selector().map(map, map_mut).into()
147    }
148
149    /// Transpose the store then coerce the contents of the Option with deref. This will only track the shallow state of the `Option`. It will
150    /// only cause a re-run if the `Option` could change from `None` to `Some` or vice versa.
151    ///
152    /// # Example
153    /// ```rust, no_run
154    /// use dioxus_stores::*;
155    /// let store = use_store(|| Some(Box::new(42)));
156    /// let derefed = store.as_deref().unwrap();
157    /// assert_eq!(derefed(), 42);
158    /// ```
159    pub fn as_deref(self) -> Option<MappedStore<T::Target, Lens>>
160    where
161        T: DerefMut,
162    {
163        self.is_some().then(move || {
164            let map: fn(&Option<T>) -> &T::Target = |value| {
165                value
166                    .as_ref()
167                    .unwrap_or_else(|| {
168                        panic!("Tried to access `Some` on an Option value");
169                    })
170                    .deref()
171            };
172            let map_mut: fn(&mut Option<T>) -> &mut T::Target = |value| {
173                value
174                    .as_mut()
175                    .unwrap_or_else(|| {
176                        panic!("Tried to access `Some` on an Option value");
177                    })
178                    .deref_mut()
179            };
180            self.into_selector().child(0, map, map_mut).into()
181        })
182    }
183
184    /// Transpose the store then filter the contents of the Option with a closure. This will always track the shallow
185    /// state of the and will track the inner state of the enum if the enum is Some.
186    ///
187    /// # Example
188    /// ```rust, no_run
189    /// use dioxus_stores::*;
190    /// let store = use_store(|| Some(42));
191    /// let option = store.filter(|&v| v > 40);
192    /// let value = option.unwrap();
193    /// assert_eq!(value(), 42);
194    /// ```
195    pub fn filter(self, f: impl FnOnce(&T) -> bool) -> Option<MappedStore<T, Lens>> {
196        self.is_some_and(f).then(move || {
197            let map: fn(&Option<T>) -> &T = |value| {
198                value.as_ref().unwrap_or_else(|| {
199                    panic!("Tried to access `Some` on an Option value");
200                })
201            };
202            let map_mut: fn(&mut Option<T>) -> &mut T = |value| {
203                value.as_mut().unwrap_or_else(|| {
204                    panic!("Tried to access `Some` on an Option value");
205                })
206            };
207            self.into_selector().child(0, map, map_mut).into()
208        })
209    }
210
211    /// Call the function with a reference to the inner value if it is Some. This will always track the shallow
212    /// state of the and will track the inner state of the enum if the enum is Some.
213    ///
214    /// # Example
215    /// ```rust, no_run
216    /// use dioxus_stores::*;
217    /// let store = use_store(|| Some(42)).inspect(|v| println!("{v}"));
218    /// ```
219    pub fn inspect(self, f: impl FnOnce(&T)) -> Self {
220        {
221            self.selector().track_shallow();
222            let value = self.selector().peek();
223            if let Some(v) = &*value {
224                self.selector().track();
225                f(v);
226            }
227        }
228        self
229    }
230}