awint_dag/mimick/
result.rs

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// the type itself must be public, but nothing else about it can
15#[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/// Mimicking `core::result::Result`, note this has a third `Opaque` variant
59/// that enables dagtime variance
60#[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            // need to write this out for some reason
119            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            // need to write this out for some reason
137            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}