reactive_graph/
trait_options.rs1use crate::{
2 traits::{
3 DefinedAt, Get, GetUntracked, Read, ReadUntracked, Track, With,
4 WithUntracked,
5 },
6 unwrap_signal,
7};
8use std::panic::Location;
9
10impl<T> DefinedAt for Option<T>
11where
12 T: DefinedAt,
13{
14 fn defined_at(&self) -> Option<&'static Location<'static>> {
15 self.as_ref().map(DefinedAt::defined_at).unwrap_or(None)
16 }
17}
18
19impl<T> Track for Option<T>
20where
21 T: Track,
22{
23 fn track(&self) {
24 if let Some(signal) = self {
25 signal.track();
26 }
27 }
28}
29
30pub trait ReadUntrackedOptional: Sized + DefinedAt {
32 type Value;
34
35 #[track_caller]
37 fn try_read_untracked(&self) -> Option<Self::Value>;
38
39 #[track_caller]
44 fn read_untracked(&self) -> Self::Value {
45 self.try_read_untracked()
46 .unwrap_or_else(unwrap_signal!(self))
47 }
48}
49
50impl<T> ReadUntrackedOptional for Option<T>
51where
52 Self: DefinedAt,
53 T: ReadUntracked,
54{
55 type Value = Option<<T as ReadUntracked>::Value>;
56
57 fn try_read_untracked(&self) -> Option<Self::Value> {
58 Some(if let Some(signal) = self {
59 Some(signal.try_read_untracked()?)
60 } else {
61 None
62 })
63 }
64}
65
66pub trait ReadOptional: DefinedAt {
68 type Value;
70
71 #[track_caller]
73 fn try_read(&self) -> Option<Self::Value>;
74
75 #[track_caller]
80 fn read(&self) -> Self::Value {
81 self.try_read().unwrap_or_else(unwrap_signal!(self))
82 }
83}
84
85impl<T> ReadOptional for Option<T>
86where
87 Self: DefinedAt,
88 T: Read,
89{
90 type Value = Option<<T as Read>::Value>;
91
92 fn try_read(&self) -> Option<Self::Value> {
93 Some(if let Some(readable) = self {
94 Some(readable.try_read()?)
95 } else {
96 None
97 })
98 }
99}
100
101pub trait WithUntrackedOptional: DefinedAt {
103 type Value: ?Sized;
105
106 #[track_caller]
109 fn try_with_untracked<U>(
110 &self,
111 fun: impl FnOnce(Option<&Self::Value>) -> U,
112 ) -> Option<U>;
113
114 #[track_caller]
119 fn with_untracked<U>(
120 &self,
121 fun: impl FnOnce(Option<&Self::Value>) -> U,
122 ) -> U {
123 self.try_with_untracked(fun)
124 .unwrap_or_else(unwrap_signal!(self))
125 }
126}
127
128impl<T> WithUntrackedOptional for Option<T>
129where
130 Self: DefinedAt,
131 T: WithUntracked,
132 <T as WithUntracked>::Value: Sized,
133{
134 type Value = <T as WithUntracked>::Value;
135
136 fn try_with_untracked<U>(
137 &self,
138 fun: impl FnOnce(Option<&Self::Value>) -> U,
139 ) -> Option<U> {
140 if let Some(signal) = self {
141 Some(signal.try_with_untracked(|val| fun(Some(val)))?)
142 } else {
143 Some(fun(None))
144 }
145 }
146}
147
148pub trait WithOptional: DefinedAt {
150 type Value: ?Sized;
152
153 #[track_caller]
156 fn try_with<U>(
157 &self,
158 fun: impl FnOnce(Option<&Self::Value>) -> U,
159 ) -> Option<U>;
160
161 #[track_caller]
166 fn with<U>(&self, fun: impl FnOnce(Option<&Self::Value>) -> U) -> U {
167 self.try_with(fun).unwrap_or_else(unwrap_signal!(self))
168 }
169}
170
171impl<T> WithOptional for Option<T>
172where
173 Self: DefinedAt,
174 T: With,
175 <T as With>::Value: Sized,
176{
177 type Value = <T as With>::Value;
178
179 fn try_with<U>(
180 &self,
181 fun: impl FnOnce(Option<&Self::Value>) -> U,
182 ) -> Option<U> {
183 if let Some(signal) = self {
184 Some(signal.try_with(|val| fun(Some(val)))?)
185 } else {
186 Some(fun(None))
187 }
188 }
189}
190
191impl<T> GetUntracked for Option<T>
192where
193 Self: DefinedAt,
194 T: GetUntracked,
195{
196 type Value = Option<<T as GetUntracked>::Value>;
197
198 fn try_get_untracked(&self) -> Option<Self::Value> {
199 Some(if let Some(signal) = self {
200 Some(signal.try_get_untracked()?)
201 } else {
202 None
203 })
204 }
205}
206
207impl<T> Get for Option<T>
208where
209 Self: DefinedAt,
210 T: Get,
211{
212 type Value = Option<<T as Get>::Value>;
213
214 fn try_get(&self) -> Option<Self::Value> {
215 Some(if let Some(signal) = self {
216 Some(signal.try_get()?)
217 } else {
218 None
219 })
220 }
221}
222
223pub trait FlattenOptionRefOption {
225 type Value;
227
228 fn flatten(&self) -> Option<&Self::Value>;
230}
231
232impl<'a, T> FlattenOptionRefOption for Option<&'a Option<T>> {
233 type Value = T;
234
235 fn flatten(&self) -> Option<&'a T> {
236 self.map(Option::as_ref).flatten()
237 }
238}