dioxus_stores/impls/
result.rs

1use std::fmt::Debug;
2
3use crate::{store::Store, MappedStore};
4use dioxus_signals::{Readable, ReadableExt, Writable};
5
6impl<Lens, T, E> Store<Result<T, E>, Lens>
7where
8    Lens: Readable<Target = Result<T, E>> + 'static,
9    T: 'static,
10    E: 'static,
11{
12    /// Checks if the `Result` is `Ok`. This will only track the shallow state of the `Result`. It will
13    /// only cause a re-run if the `Result` could change from `Err` to `Ok` or vice versa.
14    ///
15    /// # Example
16    /// ```rust, no_run
17    /// use dioxus_stores::*;
18    /// let store = use_store(|| Ok::<u32, ()>(42));
19    /// assert!(store.is_ok());
20    /// ```
21    pub fn is_ok(&self) -> bool {
22        self.selector().track_shallow();
23        self.selector().peek().is_ok()
24    }
25
26    /// Returns true if the result is Ok and the closure returns true. This will always track the shallow
27    /// state of the and will track the inner state of the enum if the enum is Ok.
28    ///
29    /// # Example
30    /// ```rust, no_run
31    /// use dioxus_stores::*;
32    /// let store = use_store(|| Ok::<u32, ()>(42));
33    /// assert!(store.is_ok_and(|v| *v == 42));
34    /// ```
35    pub fn is_ok_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
36        self.selector().track_shallow();
37        let value = self.selector().peek();
38        if let Ok(v) = &*value {
39            self.selector().track();
40            f(v)
41        } else {
42            false
43        }
44    }
45
46    /// Checks if the `Result` is `Err`. This will only track the shallow state of the `Result`. It will
47    /// only cause a re-run if the `Result` could change from `Ok` to `Err` or vice versa.
48    ///
49    /// # Example
50    /// ```rust, no_run
51    /// use dioxus_stores::*;
52    /// let store = use_store(|| Err::<(), u32>(42));
53    /// assert!(store.is_err());
54    /// ```
55    pub fn is_err(&self) -> bool {
56        self.selector().track_shallow();
57        self.selector().peek().is_err()
58    }
59
60    /// Returns true if the result is Err and the closure returns true. This will always track the shallow
61    /// state of the and will track the inner state of the enum if the enum is Err.
62    ///
63    /// # Example
64    /// ```rust, no_run
65    /// use dioxus_stores::*;
66    /// let store = use_store(|| Err::<(), u32>(42));
67    /// assert!(store.is_err_and(|v| *v == 42));
68    /// ```
69    pub fn is_err_and(&self, f: impl FnOnce(&E) -> bool) -> bool {
70        self.selector().track_shallow();
71        let value = self.selector().peek();
72        if let Err(e) = &*value {
73            self.selector().track();
74            f(e)
75        } else {
76            false
77        }
78    }
79
80    /// Converts `Store<Result<T, E>>` into `Option<Store<T>>`, discarding the error if present. This will
81    /// only track the shallow state of the `Result`. It will only cause a re-run if the `Result` could
82    /// change from `Err` to `Ok` or vice versa.
83    ///
84    /// # Example
85    /// ```rust, no_run
86    /// use dioxus_stores::*;
87    /// let store = use_store(|| Ok::<u32, ()>(42));
88    /// match store.ok() {
89    ///     Some(ok_store) => assert_eq!(ok_store(), 42),
90    ///     None => panic!("Expected Ok"),
91    /// }
92    /// ```
93    pub fn ok(self) -> Option<MappedStore<T, Lens>> {
94        let map: fn(&Result<T, E>) -> &T = |value| {
95            value.as_ref().unwrap_or_else(|_| {
96                panic!("Tried to access `ok` on an Err value");
97            })
98        };
99        let map_mut: fn(&mut Result<T, E>) -> &mut T = |value| {
100            value.as_mut().unwrap_or_else(|_| {
101                panic!("Tried to access `ok` on an Err value");
102            })
103        };
104        self.is_ok()
105            .then(|| self.into_selector().child(0, map, map_mut).into())
106    }
107
108    /// Converts `Store<Result<T, E>>` into `Option<Store<E>>`, discarding the success if present. This will
109    /// only track the shallow state of the `Result`. It will only cause a re-run if the `Result` could
110    /// change from `Ok` to `Err` or vice versa.
111    ///
112    /// # Example
113    /// ```rust, no_run
114    /// use dioxus_stores::*;
115    /// let store = use_store(|| Err::<(), u32>(42));
116    /// match store.err() {
117    ///     Some(err_store) => assert_eq!(err_store(), 42),
118    ///     None => panic!("Expected Err"),
119    /// }
120    /// ```
121    pub fn err(self) -> Option<MappedStore<E, Lens>>
122    where
123        Lens: Writable<Target = Result<T, E>> + 'static,
124    {
125        self.is_err().then(|| {
126            let map: fn(&Result<T, E>) -> &E = |value| match value {
127                Ok(_) => panic!("Tried to access `err` on an Ok value"),
128                Err(e) => e,
129            };
130            let map_mut: fn(&mut Result<T, E>) -> &mut E = |value| match value {
131                Ok(_) => panic!("Tried to access `err` on an Ok value"),
132                Err(e) => e,
133            };
134            self.into_selector().child(1, map, map_mut).into()
135        })
136    }
137
138    /// Transposes the `Store<Result<T, E>>` into a `Result<Store<T>, Store<E>>`. This will only track the
139    /// shallow state of the `Result`. It will only cause a re-run if the `Result` could change from `Err` to
140    /// `Ok` or vice versa.
141    ///
142    /// # Example
143    /// ```rust, no_run
144    /// use dioxus_stores::*;
145    /// let store = use_store(|| Ok::<u32, ()>(42));
146    /// match store.transpose() {
147    ///     Ok(ok_store) => assert_eq!(ok_store(), 42),
148    ///     Err(err_store) => assert_eq!(err_store(), ()),
149    /// }
150    /// ```
151    #[allow(clippy::result_large_err)]
152    pub fn transpose(self) -> Result<MappedStore<T, Lens>, MappedStore<E, Lens>>
153    where
154        Lens: Writable<Target = Result<T, E>> + 'static,
155    {
156        if self.is_ok() {
157            let map: fn(&Result<T, E>) -> &T = |value| match value {
158                Ok(t) => t,
159                Err(_) => panic!("Tried to access `ok` on an Err value"),
160            };
161            let map_mut: fn(&mut Result<T, E>) -> &mut T = |value| match value {
162                Ok(t) => t,
163                Err(_) => panic!("Tried to access `ok` on an Err value"),
164            };
165            Ok(self.into_selector().child(0, map, map_mut).into())
166        } else {
167            let map: fn(&Result<T, E>) -> &E = |value| match value {
168                Ok(_) => panic!("Tried to access `err` on an Ok value"),
169                Err(e) => e,
170            };
171            let map_mut: fn(&mut Result<T, E>) -> &mut E = |value| match value {
172                Ok(_) => panic!("Tried to access `err` on an Ok value"),
173                Err(e) => e,
174            };
175            Err(self.into_selector().child(1, map, map_mut).into())
176        }
177    }
178
179    /// Unwraps the `Result` and returns a `Store<T>`. This will only track the shallow state of the `Result`.
180    /// It will only cause a re-run if the `Result` could change from `Err` to `Ok` or vice versa.
181    ///
182    /// # Example
183    /// ```rust, no_run
184    /// use dioxus_stores::*;
185    /// let store = use_store(|| Ok::<u32, ()>(42));
186    /// let unwrapped = store.unwrap();
187    /// assert_eq!(unwrapped(), 42);
188    /// ```
189    pub fn unwrap(self) -> MappedStore<T, Lens>
190    where
191        Lens: Writable<Target = Result<T, E>> + 'static,
192        E: Debug,
193    {
194        self.transpose().unwrap()
195    }
196
197    /// Expects the `Result` to be `Ok` and returns a `Store<T>`. If the value is `Err`, this will panic with `msg`.
198    /// This will only track the shallow state of the `Result`. It will only cause a re-run if the `Result` could
199    /// change from `Err` to `Ok` or vice versa.
200    ///
201    /// # Example
202    /// ```rust, no_run
203    /// use dioxus_stores::*;
204    /// let store = use_store(|| Ok::<u32, ()>(42));
205    /// let unwrapped = store.expect("Expected Ok");
206    /// assert_eq!(unwrapped(), 42);
207    /// ```
208    pub fn expect(self, msg: &str) -> MappedStore<T, Lens>
209    where
210        Lens: Writable<Target = Result<T, E>> + 'static,
211        E: Debug,
212    {
213        self.transpose().expect(msg)
214    }
215
216    /// Unwraps the error variant of the `Result`. This will only track the shallow state of the `Result`.
217    /// It will only cause a re-run if the `Result` could change from `Ok` to `Err` or vice versa.
218    ///
219    /// # Example
220    /// ```rust, no_run
221    /// use dioxus_stores::*;
222    /// let store = use_store(|| Err::<(), u32>(42));
223    /// let unwrapped_err = store.unwrap_err();
224    /// assert_eq!(unwrapped_err(), 42);
225    /// ```
226    pub fn unwrap_err(self) -> MappedStore<E, Lens>
227    where
228        Lens: Writable<Target = Result<T, E>> + 'static,
229        T: Debug,
230    {
231        self.transpose().unwrap_err()
232    }
233
234    /// Expects the `Result` to be `Err` and returns a `Store<E>`. If the value is `Ok`, this will panic with `msg`.
235    /// This will only track the shallow state of the `Result`. It will only cause a re-run if the `Result` could
236    /// change from `Ok` to `Err` or vice versa.
237    ///
238    /// # Example
239    /// ```rust, no_run
240    /// use dioxus_stores::*;
241    /// let store = use_store(|| Err::<(), u32>(42));
242    /// let unwrapped_err = store.expect_err("Expected Err");
243    /// assert_eq!(unwrapped_err(), 42);
244    /// ```
245    pub fn expect_err(self, msg: &str) -> MappedStore<E, Lens>
246    where
247        Lens: Writable<Target = Result<T, E>> + 'static,
248        T: Debug,
249    {
250        self.transpose().expect_err(msg)
251    }
252
253    /// Call the function with a reference to the inner value if it is Ok. This will always track the shallow
254    /// state of the and will track the inner state of the enum if the enum is Ok.
255    ///
256    /// # Example
257    /// ```rust, no_run
258    /// use dioxus_stores::*;
259    /// let store = use_store(|| Ok::<u32, ()>(42)).inspect(|v| println!("{v}"));
260    /// ```
261    pub fn inspect(self, f: impl FnOnce(&T)) -> Self
262    where
263        Lens: Writable<Target = Result<T, E>> + 'static,
264    {
265        {
266            self.selector().track_shallow();
267            let value = self.selector().peek();
268            if let Ok(value) = &*value {
269                self.selector().track();
270                f(value);
271            }
272        }
273        self
274    }
275
276    /// Call the function with a mutable reference to the inner value if it is Err. This will always track the shallow
277    /// state of the `Result` and will track the inner state of the enum if the enum is Err.
278    ///
279    /// # Example
280    /// ```rust, no_run
281    /// use dioxus_stores::*;
282    /// let store = use_store(|| Err::<(), u32>(42)).inspect_err(|v| println!("{v}"));
283    /// ```
284    pub fn inspect_err(self, f: impl FnOnce(&E)) -> Self
285    where
286        Lens: Writable<Target = Result<T, E>> + 'static,
287    {
288        {
289            self.selector().track_shallow();
290            let value = self.selector().peek();
291            if let Err(value) = &*value {
292                self.selector().track();
293                f(value);
294            }
295        }
296        self
297    }
298
299    /// Transpose the store then coerce the contents of the Result with deref. This will only track the shallow state of the `Result`. It will
300    /// only cause a re-run if the `Result` could change from `Err` to `Ok` or vice versa.
301    ///
302    /// # Example
303    /// ```rust, no_run
304    /// use dioxus_stores::*;
305    /// let store = use_store(|| Ok::<Box<u32>, ()>(Box::new(42)));
306    /// let derefed = store.as_deref().unwrap();
307    /// assert_eq!(derefed(), 42);
308    /// ```
309    pub fn as_deref(self) -> Result<MappedStore<T::Target, Lens>, MappedStore<E, Lens>>
310    where
311        Lens: Writable<Target = Result<T, E>> + 'static,
312        T: std::ops::DerefMut,
313    {
314        if self.is_ok() {
315            let map: fn(&Result<T, E>) -> &T::Target = |value| match value {
316                Ok(t) => t.deref(),
317                Err(_) => panic!("Tried to access `ok` on an Err value"),
318            };
319            let map_mut: fn(&mut Result<T, E>) -> &mut T::Target = |value| match value {
320                Ok(t) => t.deref_mut(),
321                Err(_) => panic!("Tried to access `ok` on an Err value"),
322            };
323            Ok(self.into_selector().child(0, map, map_mut).into())
324        } else {
325            let map: fn(&Result<T, E>) -> &E = |value| match value {
326                Ok(_) => panic!("Tried to access `err` on an Ok value"),
327                Err(e) => e,
328            };
329            let map_mut: fn(&mut Result<T, E>) -> &mut E = |value| match value {
330                Ok(_) => panic!("Tried to access `err` on an Ok value"),
331                Err(e) => e,
332            };
333            Err(self.into_selector().child(1, map, map_mut).into())
334        }
335    }
336}