1use either::Either;
2
3use crate::{Func, HasValues};
4
5pub trait OpValue<F: Func, O>: Sized {
6 type Residue;
7 type Capture: HasValues<F>;
8 type Spit;
9 fn disasm(self, f: &mut F) -> Result<(O, Self::Capture, Self::Spit), Self::Residue>;
10 fn of(f: &mut F, o: O, c: Self::Capture, s: Self::Spit) -> Option<Self>;
11 fn lift(f: &mut F, r: Self::Residue) -> Option<Self>;
12}
13
14impl<F: Func, A, B, T: OpValue<F, A, Residue: OpValue<F, B>>> OpValue<F, Either<A, B>> for T {
15 type Residue = <T::Residue as OpValue<F, B>>::Residue;
16
17 type Capture = Either<T::Capture, <T::Residue as OpValue<F, B>>::Capture>;
18
19 type Spit = Either<T::Spit, <T::Residue as OpValue<F, B>>::Spit>;
20
21 fn disasm(self, f: &mut F) -> Result<(Either<A, B>, Self::Capture, Self::Spit), Self::Residue> {
22 match self.disasm(f) {
23 Ok((a, b, c)) => Ok((Either::Left(a), Either::Left(b), Either::Left(c))),
24 Err(d) => match d.disasm(f) {
25 Err(e) => Err(e),
26 Ok((a, b, c)) => Ok((Either::Right(a), Either::Right(b), Either::Right(c))),
27 },
28 }
29 }
30
31 fn of(f: &mut F, o: Either<A, B>, c: Self::Capture, s: Self::Spit) -> Option<T> {
32 match (o, c, s) {
33 (Either::Left(o), Either::Left(c), Either::Left(s)) => {
34 <T as OpValue<F, A>>::of(f, o, c, s)
35 }
36 (Either::Right(o), Either::Right(c), Either::Right(s)) => {
37 <T::Residue as OpValue<F, B>>::of(f, o, c, s)
38 .and_then(|b| <T as OpValue<F, A>>::lift(f, b))
39 }
40 _ => None,
41 }
42 }
43
44 fn lift(f: &mut F, r: Self::Residue) -> Option<T> {
45 <T::Residue as OpValue<F, B>>::lift(f, r).and_then(|b| <T as OpValue<F, A>>::lift(f, b))
46 }
47}