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}