1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use crate::func::{applicative_select::*, fail::*, *};

type Frwa<'a, A, E0, E1, Fallible> =
    Wrap<'a, Result<WrapE<'a, A, E0, Fallible>, E1>, <Fallible as MonadFailAny<'a>>::T>;

type Wwa<'a, A, E0, E1, Fallible> = WrapE<'a, WrapE<'a, A, E0, Fallible>, E1, Fallible>;

trait SpeculativeFailImpl<'a>: MonadFailAny<'a> {
    fn speculative_a_wb<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
        a: A,
        wb: WrapE<'a, B, E0, Self>,
    ) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
        Self::map_err(<Self::W<E0> as Functor>::fmap(wb, |b| (a, b)), Ok)
    }

    fn speculative_ra_wb<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
        ra: Result<A, E0>,
        wb: WrapE<'a, B, E0, Self>,
    ) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
        match ra {
            Ok(a) => Self::speculative_a_wb(a, wb),
            Err(e0) => Self::fail(Ok(e0)),
        }
    }

    fn speculative_ra_rwb<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
        ra: Result<A, E0>,
        rwb: Result<WrapE<'a, B, E0, Self>, E1>,
    ) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
        match rwb {
            Ok(wb) => Self::speculative_ra_wb(ra, wb),
            Err(e1) => Self::fail(Err(e1)),
        }
    }

    fn speculative_ra_frwb<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
        ra: Result<A, E0>,
        frwb: Frwa<'a, B, E0, E1, Self>,
    ) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
        Self::stuff(<Self::T as Monad>::bind(frwb, |rwb| {
            Self::unstuff(Self::speculative_ra_rwb(ra, rwb))
        }))
    }

    fn speculative_fra_wb<A: 'a + Send, B: 'a + Send, E0: 'a + Send>(
        fra: Wrap<'a, Result<A, E0>, Self::T>,
        wb: WrapE<'a, B, E0, Self>,
    ) -> WrapE<'a, (A, B), E0, Self> {
        <Self::W<E0> as ApplicativeTuple>::tuple((Self::stuff(fra), wb))
    }

    fn speculative_wa_frwb<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
        wa: WrapE<'a, A, E0, Self>,
        frwb: Frwa<'a, B, E0, E1, Self>,
    ) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
        Self::stuff(<<Self as MonadFailAny>::T as Monad>::join(
            <<Self as MonadFailAny>::T as Functor>::fmap(
                Self::T::select_map(Self::unstuff(wa), frwb, |selected| match selected {
                    Selected::A(ra, frwb) => Self::speculative_ra_frwb(ra, frwb),
                    Selected::B(fra, Ok(wb)) => {
                        Self::map_err(Self::speculative_fra_wb(fra, wb), Ok)
                    }
                    Selected::B(_, Err(e1)) => Self::fail(Err(e1)),
                }),
                Self::unstuff,
            ),
        ))
    }

    fn speculative_frwa_wb<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
        frwa: Frwa<'a, A, E0, E1, Self>,
        wb: WrapE<'a, B, E0, Self>,
    ) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
        <Self::W<Result<E0, E1>> as Functor>::fmap(Self::speculative_wa_frwb(wb, frwa), |(b, a)| {
            (a, b)
        })
    }

    fn speculative_impl<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
        wwa: Wwa<'a, A, E0, E1, Self>,
        wwb: Wwa<'a, B, E0, E1, Self>,
    ) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
        Self::stuff(<Self::T as Monad>::join(<Self::T as Functor>::fmap(
            Self::T::select_map(
                Self::unstuff(wwa),
                Self::unstuff(wwb),
                |selected| match selected {
                    Selected::A(Ok(wa), frwb) => Self::speculative_wa_frwb(wa, frwb),
                    Selected::A(Err(e1), _) => Self::fail(Err(e1)),
                    Selected::B(frwa, Ok(wb)) => Self::speculative_frwa_wb(frwa, wb),
                    Selected::B(_, Err(e1)) => Self::fail(Err(e1)),
                },
            ),
            Self::unstuff,
        )))
    }
}

pub trait SpeculativeFail<'a>: MonadFailAny<'a> {
    fn speculative<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
        wwa: Wwa<'a, A, E0, E1, Self>,
        wwb: Wwa<'a, B, E0, E1, Self>,
    ) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
        Self::speculative_impl(wwa, wwb)
    }
}

impl<'a, Fallible: ?Sized + MonadFailAny<'a>> SpeculativeFailImpl<'a> for Fallible {}
impl<'a, Fallible: ?Sized + MonadFailAny<'a>> SpeculativeFail<'a> for Fallible {}