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
use super::{fail::*, *};

pub type WrapC<'a, A, Ctx> = Wrap<'a, A, <Ctx as FunctorContext<'a>>::T>;

pub trait FunctorContext<'a>: 'a + Send {
    type T: WeakFunctor<'a>;
}

pub trait MonadContext<'a>: FunctorContext<'a, T = Self::_Tm> {
    type _Tm: Monad<'a>;
}

impl<'a, Ctx: FunctorContext<'a>> MonadContext<'a> for Ctx
where
    Ctx::T: Monad<'a>,
{
    type _Tm = Ctx::T;
}

pub trait FunctorContextExt<'a>: FunctorContext<'a> {
    fn fmap<A: 'a + Send, B: 'a + Send>(
        fa: WrapC<'a, A, Self>,
        f: impl 'a + Send + FnOnce(A) -> B,
    ) -> WrapC<'a, B, Self>
    where
        Self::T: Functor<'a>,
    {
        <Self::T as Functor>::fmap(fa, f)
    }

    fn pure<A: 'a + Send>(a: A) -> WrapC<'a, A, Self>
    where
        Self::T: Pure<'a>,
    {
        <Self::T as Pure>::pure(a)
    }

    fn bind<A: 'a + Send, B: 'a + Send>(
        fa: WrapC<'a, A, Self>,
        f: impl 'a + Send + FnOnce(A) -> WrapC<'a, B, Self>,
    ) -> WrapC<'a, B, Self>
    where
        Self::T: Monad<'a>,
    {
        <Self::T as Monad>::bind(fa, f)
    }

    fn fail<A: 'a + Send, E: 'a + Send>(e: E) -> WrapC<'a, A, Self>
    where
        Self::T: Fail<'a, E>,
    {
        <Self::T as Fail<_>>::fail(e)
    }
}

impl<'a, Ctx: FunctorContext<'a>> FunctorContextExt<'a> for Ctx {}

pub trait FallibleCtx<'a>: FunctorContext<'a> {
    /// Type to allow improved support for [`Result`] evaluation.
    /// This is important for async applications stopping early.
    type Fallible: MonadFailAny<'a, T = Self::T>;
}

/// Preferred monad for fallible uses.
pub type FallibleMonad<'a, Ctx, E> = <<Ctx as FallibleCtx<'a>>::Fallible as MonadFailAny<'a>>::W<E>;

/// Preferred [Wrap]ped [Result].
pub type FallibleWrapped<'a, Ctx, A, E> = Wrap<'a, A, FallibleMonad<'a, Ctx, E>>;

/// Extention trait for simpler conversion between [`FunctorContext::T`] and [`FallibleCtx::Fallible`].
///
/// this is the preferred way to switch between [WrapC] and [FallibleWrapped].
pub trait FallibleCtxExt<'a>: FallibleCtx<'a> {
    /// Convert a fallible wrapped into a wrapped result.
    fn unstuff<A: 'a + Send, E: 'a + Send>(
        wa: FallibleWrapped<'a, Self, A, E>,
    ) -> WrapC<'a, Result<A, E>, Self> {
        Self::Fallible::unstuff(wa)
    }

    /// Convert a wrapped result into a fallible wrapped.
    fn stuff<A: 'a + Send, E: 'a + Send>(
        fa: WrapC<'a, Result<A, E>, Self>,
    ) -> FallibleWrapped<'a, Self, A, E> {
        Self::Fallible::stuff(fa)
    }
}

impl<'a, Ctx: FallibleCtx<'a>> FallibleCtxExt<'a> for Ctx {}