1use core::result::Result as StdResult;
2use std::{
3 borrow::{Borrow, BorrowMut},
4 fmt::Debug,
5 ops::{Deref, DerefMut},
6 process::{ExitCode, Termination},
7};
8
9use awint_ext::{awi, awint_internals::Location};
10use StdResult::{Err as StdErr, Ok as StdOk};
11
12use crate::{dag, epoch::register_assertion_bit_for_current_epoch, mimick::*};
13
14#[derive(Debug, Clone, Copy)]
16#[doc(hidden)]
17pub struct OpaqueInternal<T, E> {
18 pub(in crate::mimick) is_ok: dag::bool,
19 pub(in crate::mimick) res: StdResult<T, E>,
20}
21
22impl<T, E> OpaqueInternal<T, E> {
23 fn as_ref(&self) -> OpaqueInternal<&T, &E> {
24 OpaqueInternal {
25 is_ok: self.is_ok,
26 res: self.res.as_ref(),
27 }
28 }
29
30 fn as_mut(&mut self) -> OpaqueInternal<&mut T, &mut E> {
31 OpaqueInternal {
32 is_ok: self.is_ok,
33 res: self.res.as_mut(),
34 }
35 }
36
37 fn copied(self) -> OpaqueInternal<T, E>
38 where
39 T: Clone,
40 {
41 OpaqueInternal {
42 is_ok: self.is_ok,
43 res: self.res,
44 }
45 }
46
47 fn cloned(self) -> OpaqueInternal<T, E>
48 where
49 T: Clone,
50 {
51 OpaqueInternal {
52 is_ok: self.is_ok,
53 res: self.res,
54 }
55 }
56}
57
58#[must_use]
61#[derive(Debug, Clone, Copy)]
62pub enum Result<T, E> {
63 Ok(T),
64 Err(E),
65 Opaque(OpaqueInternal<T, E>),
66}
67
68use crate::mimick::Result::Opaque;
69pub use crate::mimick::Result::{Err, Ok};
70
71impl<T, E> From<awi::Result<T, E>> for dag::Result<T, E> {
72 fn from(value: awi::Result<T, E>) -> Self {
73 match value {
74 awi::Ok(t) => Ok(t),
75 awi::Err(e) => Err(e),
76 }
77 }
78}
79
80impl<T, E> Result<T, E> {
81 pub fn ok_at_dagtime(t: T, is_ok: dag::bool) -> Self {
82 Opaque(OpaqueInternal {
83 is_ok,
84 res: awi::Ok(t),
85 })
86 }
87
88 pub fn err_at_dagtime(e: E, is_err: dag::bool) -> Self {
89 Opaque(OpaqueInternal {
90 is_ok: !is_err,
91 res: awi::Err(e),
92 })
93 }
94
95 pub fn as_ref(&self) -> Result<&T, &E> {
96 match *self {
97 Ok(ref t) => Ok(t),
98 Err(ref e) => Err(e),
99 Opaque(ref z) => Opaque(z.as_ref()),
100 }
101 }
102
103 pub fn as_mut(&mut self) -> Result<&mut T, &mut E> {
104 match *self {
105 Ok(ref mut t) => Ok(t),
106 Err(ref mut e) => Err(e),
107 Opaque(ref mut z) => Opaque(z.as_mut()),
108 }
109 }
110
111 pub fn as_deref(&self) -> Result<&<T as Deref>::Target, &E>
112 where
113 T: Deref,
114 {
115 match self.as_ref() {
116 Ok(t) => Ok(t),
117 Err(e) => Err(e),
118 Opaque(z) => Opaque(OpaqueInternal {
120 is_ok: z.is_ok,
121 res: match z.res {
122 StdOk(t) => StdOk(Deref::deref(t)),
123 StdErr(e) => StdErr(e),
124 },
125 }),
126 }
127 }
128
129 pub fn as_deref_mut(&mut self) -> Result<&mut <T as Deref>::Target, &mut E>
130 where
131 T: DerefMut,
132 {
133 match self.as_mut() {
134 Ok(t) => Ok(t),
135 Err(e) => Err(e),
136 Opaque(z) => Opaque(OpaqueInternal {
138 is_ok: z.is_ok,
139 res: match z.res {
140 StdErr(e) => StdErr(e),
141 StdOk(t) => StdOk(DerefMut::deref_mut(t)),
142 },
143 }),
144 }
145 }
146
147 pub fn copied(self) -> Result<T, E>
148 where
149 T: Copy,
150 {
151 match self {
152 Ok(t) => Ok(t),
153 Err(e) => Err(e),
154 Opaque(z) => Opaque(z.copied()),
155 }
156 }
157
158 pub fn cloned(self) -> Result<T, E>
159 where
160 T: Clone,
161 {
162 match self {
163 Ok(t) => Ok(t),
164 Err(e) => Err(e),
165 Opaque(z) => Opaque(z.cloned()),
166 }
167 }
168
169 #[must_use]
170 pub fn is_ok_at_runtime(&self) -> bool {
171 match self {
172 Ok(_) => true,
173 Err(_) => false,
174 Opaque(_) => false,
175 }
176 }
177
178 #[must_use]
179 pub fn is_ok(&self) -> dag::bool {
180 match self {
181 Ok(_) => true.into(),
182 Err(_) => false.into(),
183 Opaque(z) => z.is_ok,
184 }
185 }
186
187 #[must_use]
188 pub fn is_err_at_runtime(&self) -> bool {
189 match self {
190 Ok(_) => false,
191 Err(_) => true,
192 Opaque(_) => false,
193 }
194 }
195
196 #[must_use]
197 pub fn is_err(&self) -> dag::bool {
198 match self {
199 Ok(_) => false.into(),
200 Err(_) => true.into(),
201 Opaque(z) => !z.is_ok,
202 }
203 }
204
205 #[must_use]
206 pub fn is_opaque_at_runtime(&self) -> bool {
207 match self {
208 Ok(_) => false,
209 Err(_) => false,
210 Opaque(_) => false,
211 }
212 }
213
214 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Result<U, E> {
215 match self {
216 Ok(t) => Ok(f(t)),
217 Err(e) => Err(e),
218 Opaque(z) => Opaque(OpaqueInternal {
219 is_ok: z.is_ok,
220 res: z.res.map(f),
221 }),
222 }
223 }
224
225 #[must_use]
226 pub fn ok(self) -> dag::Option<T> {
227 match self {
228 Ok(t) => dag::Some(t),
229 Err(_) => dag::None,
230 Opaque(z) => dag::Option::Opaque(crate::mimick::option::OpaqueInternal {
231 is_some: z.is_ok,
232 t: match z.res {
233 StdOk(t) => awi::Some(t),
234 StdErr(_) => awi::None,
235 },
236 }),
237 }
238 }
239
240 #[must_use]
241 pub fn err(self) -> dag::Option<E> {
242 match self {
243 Ok(_) => dag::None,
244 Err(e) => dag::Some(e),
245 Opaque(z) => dag::Option::Opaque(crate::mimick::option::OpaqueInternal {
246 is_some: !z.is_ok,
247 t: match z.res {
248 StdOk(_) => awi::None,
249 StdErr(e) => awi::Some(e),
250 },
251 }),
252 }
253 }
254
255 #[track_caller]
256 pub fn unwrap_at_runtime(self) -> T
257 where
258 E: Debug,
259 {
260 match self {
261 Ok(t) => t,
262 Err(e) => panic!("called `Result::unwrap_at_runtime()` on an `Err` value: {e:?}"),
263 Opaque(_) => panic!("called `Result::unwrap_at_runtime()` on an `Opaque` value"),
264 }
265 }
266
267 #[track_caller]
268 pub fn unwrap(self) -> T
269 where
270 E: Debug,
271 {
272 match self {
273 Ok(t) => t,
274 Err(e) => panic!("called `Result::unwrap()` on an `Err` value: {e:?}"),
275 Opaque(z) => {
276 let tmp = std::panic::Location::caller();
277 let location = Location {
278 file: tmp.file(),
279 line: tmp.line(),
280 col: tmp.column(),
281 };
282 register_assertion_bit_for_current_epoch(z.is_ok, location);
283 if let StdOk(t) = z.res {
284 t
285 } else {
286 panic!("called `Result::unwrap()` on an error-type `Opaque` value")
287 }
288 }
289 }
290 }
291
292 #[track_caller]
293 pub fn unwrap_err(self) -> E
294 where
295 T: Debug,
296 {
297 match self {
298 Ok(t) => panic!("called `Result::unwrap_err()` on an `Ok` value: {t:?}"),
299 Err(e) => e,
300 Opaque(z) => {
301 let tmp = std::panic::Location::caller();
302 let location = Location {
303 file: tmp.file(),
304 line: tmp.line(),
305 col: tmp.column(),
306 };
307 register_assertion_bit_for_current_epoch(!z.is_ok, location);
308 if let StdErr(e) = z.res {
309 e
310 } else {
311 panic!("called `Result::unwrap()` on an ok-type `Opaque` value")
312 }
313 }
314 }
315 }
316}
317
318impl<T: Borrow<Bits> + BorrowMut<Bits>, E> Result<T, E> {
319 #[track_caller]
320 pub fn unwrap_or(self, default: T) -> T {
321 match self {
322 Ok(t) => t,
323 Err(_) => default,
324 Opaque(z) => match z.res {
325 StdOk(mut t) => {
326 if t.borrow_mut()
327 .mux_(default.borrow(), z.is_ok)
328 .is_none_at_runtime()
329 {
330 panic!("called `Result::unwrap_or()` with unequal bitwidth types")
331 }
332 t
333 }
334 StdErr(_) => {
335 panic!("called `Result::unwrap_or()` with error-type `Opaque`")
336 }
337 },
338 }
339 }
340}
341
342impl<T, E> Termination for Result<T, E> {
343 fn report(self) -> ExitCode {
344 match self {
345 Ok(_) => ExitCode::SUCCESS,
346 Err(_) => ExitCode::FAILURE,
347 Opaque(z) => match z.res {
348 StdOk(_) => ExitCode::SUCCESS,
349 StdErr(_) => ExitCode::FAILURE,
350 },
351 }
352 }
353}
354
355#[cfg(feature = "try_support")]
356impl<T, E> std::ops::Residual<T> for Result<!, E> {
357 type TryType = Result<T, E>;
358}
359
360#[cfg(feature = "try_support")]
361impl<T, E, F: From<E>> std::ops::FromResidual<Result<!, E>> for Result<T, F> {
362 fn from_residual(residual: Result<!, E>) -> Self {
363 match residual {
364 Err(e) => Err(From::from(e)),
365 _ => unreachable!(),
366 }
367 }
368}
369
370#[cfg(feature = "try_support")]
371impl<T, E> std::ops::Try for Result<T, E> {
372 type Output = T;
373 type Residual = Result<!, E>;
374
375 fn from_output(output: Self::Output) -> Self {
376 Ok(output)
377 }
378
379 #[track_caller]
380 fn branch(self) -> std::ops::ControlFlow<Self::Residual, Self::Output> {
381 use std::ops::ControlFlow;
382 match self {
383 Ok(t) => ControlFlow::Continue(t),
384 Err(e) => ControlFlow::Break(Err(e)),
385 Opaque(z) => match z.res {
386 StdOk(t) => {
387 let tmp = std::panic::Location::caller();
388 let location = Location {
389 file: tmp.file(),
390 line: tmp.line(),
391 col: tmp.column(),
392 };
393 register_assertion_bit_for_current_epoch(z.is_ok, location);
394 ControlFlow::Continue(t)
395 }
396 StdErr(e) => {
397 let tmp = std::panic::Location::caller();
398 let location = Location {
399 file: tmp.file(),
400 line: tmp.line(),
401 col: tmp.column(),
402 };
403 register_assertion_bit_for_current_epoch(!z.is_ok, location);
404 ControlFlow::Break(Err(e))
405 }
406 },
407 }
408 }
409}