1use cgp_core::prelude::*;
2use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent};
3
4use crate::monadic::ident::IdentMonadic;
5use crate::traits::{ContainsValue, LiftValue, MonadicBind, MonadicTrans};
6
7pub struct ErrMonadic;
8
9pub struct ErrMonadicTrans<M>(pub PhantomData<M>);
10
11impl<M> MonadicTrans<M> for ErrMonadic {
12 type M = ErrMonadicTrans<M>;
13}
14
15impl<M1, M2, M3> MonadicTrans<M2> for ErrMonadicTrans<M1>
16where
17 M1: MonadicTrans<M2, M = M3>,
18{
19 type M = ErrMonadicTrans<M3>;
20}
21
22impl<M, Provider> MonadicBind<Provider> for ErrMonadicTrans<M>
23where
24 M: MonadicBind<BindErr<M, Provider>>,
25{
26 type Provider = M::Provider;
27}
28
29impl<Provider> MonadicBind<Provider> for ErrMonadic {
30 type Provider = BindErr<IdentMonadic, Provider>;
31}
32pub struct BindErr<M, Cont>(pub PhantomData<(M, Cont)>);
33
34impl<T, E> ContainsValue<Result<T, E>> for ErrMonadic {
35 type Value = T;
36}
37
38impl<T, E> LiftValue<T, Result<T, E>> for ErrMonadic {
39 type Output = Result<T, E>;
40
41 fn lift_value(value: T) -> Self::Output {
42 Ok(value)
43 }
44
45 fn lift_output(output: Result<T, E>) -> Self::Output {
46 output
47 }
48}
49
50impl<T, E, V, M> ContainsValue<V> for ErrMonadicTrans<M>
51where
52 M: ContainsValue<V, Value = Result<T, E>>,
53{
54 type Value = T;
55}
56
57impl<T, E, V, M> LiftValue<T, V> for ErrMonadicTrans<M>
58where
59 M: ContainsValue<V, Value = Result<T, E>> + LiftValue<Result<T, E>, V>,
60{
61 type Output = M::Output;
62
63 fn lift_value(value: T) -> Self::Output {
64 M::lift_value(Ok(value))
65 }
66
67 fn lift_output(output: V) -> Self::Output {
68 M::lift_output(output)
69 }
70}
71
72#[cgp_provider]
73impl<Context, Code, T1, T2, E, M, Cont> Computer<Context, Code, Result<T1, E>> for BindErr<M, Cont>
74where
75 Cont: Computer<Context, Code, T1>,
76 M: ContainsValue<Cont::Output, Value = Result<T2, E>> + LiftValue<Result<T2, E>, Cont::Output>,
77{
78 type Output = M::Output;
79
80 fn compute(context: &Context, code: PhantomData<Code>, input: Result<T1, E>) -> Self::Output {
81 match input {
82 Ok(value) => M::lift_output(Cont::compute(context, code, value)),
83 Err(err) => M::lift_value(Err(err)),
84 }
85 }
86}
87
88#[cgp_provider]
89impl<Context, Code, T1, T2, E, M, Cont> AsyncComputer<Context, Code, Result<T1, E>>
90 for BindErr<M, Cont>
91where
92 Cont: AsyncComputer<Context, Code, T1>,
93 M: ContainsValue<Cont::Output, Value = Result<T2, E>> + LiftValue<Result<T2, E>, Cont::Output>,
94{
95 type Output = M::Output;
96
97 async fn compute_async(
98 context: &Context,
99 code: PhantomData<Code>,
100 input: Result<T1, E>,
101 ) -> Self::Output {
102 match input {
103 Ok(value) => M::lift_output(Cont::compute_async(context, code, value).await),
104 Err(err) => M::lift_value(Err(err)),
105 }
106 }
107}