1use core::marker::PhantomData;
2use core::mem::ManuallyDrop;
3use crate::bool::choose;
4use crate::guard::Guard;
5use crate::term::Value;
6use crate::var::Var;
7use crate::transmutable::{coerce, Equiv};
8use crate::term::ValueEq;
9use crate::{bool::{False, True}, term::Term};
10
11#[repr(C)]
12pub union DResult<B: Term<Type = bool>, T, F> {
13 phantom: PhantomData<Value<B>>,
14 t: ManuallyDrop<T>,
15 f: ManuallyDrop<F>,
16}
17
18impl<B: Term<Type = bool>, T, F> Drop for DResult<B, T, F> {
19 #[inline(always)]
20 fn drop(&mut self) {
21 link_error!("DResult types are linear types that cannot be allowed to be dropped, instead use into() or into_result() so that the proper destructor is run");
22 }
23}
24
25impl<T, F> DResult<True, T, F> {
26 pub fn into(mut self) -> T {
27 let r = unsafe {ManuallyDrop::take(&mut self.t)};
28 core::mem::forget(self);
29 r
30 }
31
32 pub fn new(t: T) -> Self {
33 DResult {t: ManuallyDrop::new(t)}
34 }
35}
36
37impl<T, F> DResult<False, T, F> {
38 pub fn into(mut self) -> F {
39 let r = unsafe {ManuallyDrop::take(&mut self.f)};
40 core::mem::forget(self);
41 r
42 }
43
44 pub fn new(f: F) -> Self {
45 DResult {f: ManuallyDrop::new(f)}
46 }
47}
48
49impl<B: Term<Type = bool>, T, F> DResult<B, T, F> {
50 pub fn equiv<B1: Term<Type = bool>>(_: ValueEq<B, B1>) -> Equiv<DResult<B, T, F>, DResult<B1, T, F>> {
51 unsafe {Equiv::axiom()}
52 }
53}
54
55impl<'a, T, F> DResult<Var<'a, bool>, T, F> {
56 pub fn from(guard: Guard<'a>, x: Result<T, F>) -> (Self, Result<ValueEq<Var<'a, bool>, True>, ValueEq<Var<'a, bool>, False>>) {
57 match x {
58 Ok(t) => {
59 let eq = Var::erase(guard);
60 let r = DResult::<True, _, _>::new(t);
61 let r = coerce(r, DResult::equiv(eq));
62 (r, Ok(-eq))
63 }
64 Err(f) => {
65 let eq = Var::erase(guard);
66 let r = DResult::<False, _, _>::new(f);
67 let r = coerce(r, DResult::equiv(eq));
68 (r, Err(-eq))
69 }
70 }
71 }
72}
73
74impl<B: Term<Type = bool>, T, F> DResult<B, T, F> {
75 pub fn into_result(r: DResult<B, T, F>, b: Value<B>) -> Result<T, F> {
76 match choose(b) {
77 Ok(eq) => {
78 let r = coerce(r, DResult::equiv(eq));
79 Ok(r.into())
80 },
81 Err(eq) => {
82 let r = coerce(r, DResult::equiv(eq));
83 Err(r.into())
84 }
85 }
86 }
87}