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}