error_combinator/
check.rs

1use std::marker::PhantomData;
2
3use crate::cmberr::{
4    CombineErrorBuilder,
5    CombineError
6};
7
8pub trait Check<T, PreState> 
9    where Self:Sized
10{
11    type PostState;
12    type Error;
13
14    fn check(self, value: CheckState<T, PreState>)
15        -> CheckOutcome<T, Self::PostState, Self::Error>;
16
17    fn and<B, C>(self, b: B) -> And<Self, B, C>
18        where
19            B: Check<T, Self::PostState>,
20            C: CombineErrorBuilder<Self::Error, B::Error>
21    {
22        And { a: self, b, _combine:PhantomData }
23    }
24
25    fn or<B, C>(self, b: B) -> Or<Self, B, C>
26        where 
27            B: Check<T, Self::PostState>,
28            C: CombineErrorBuilder<Self::Error, B::Error>
29    {
30        Or { a: self, b, _combine: PhantomData }
31    }
32}
33
34pub enum CheckOutcome<T, State, E> {
35    Passed(CheckState<T, State>),
36    Failed{
37        state: CheckState<T, State>,
38        err: E
39    },
40}
41
42impl<T, State, E> CheckOutcome<T, State, E> {
43    pub fn to_result(self) -> Result<T, E> {
44        match self {
45            CheckOutcome::Passed(v) => {
46                Ok(v.value)
47            }
48            CheckOutcome::Failed{state:_, err} => {
49                Err(err)
50            }
51        }
52    }
53
54    pub fn to_result_with_data(self) -> Result<T, (T, E)> {
55        match self {
56            CheckOutcome::Passed(v) => {
57                Ok(v.value)
58            }
59            CheckOutcome::Failed{state, err} => {
60                Err((state.value, err))
61            }
62        }
63    }
64}
65
66pub struct CheckState<T: Sized, S> 
67    where Self: Sized 
68{
69    pub value: T,
70    _state: PhantomData<S>
71}
72
73impl<T, S> CheckState<T, S> {
74    pub fn new(value: T) -> Self {
75        Self { value, _state: PhantomData }
76    }
77}
78
79pub struct And<A, B, C> {
80    a: A,
81    b: B,
82    _combine: PhantomData<C>
83}
84
85impl<T, PreState, A, B, C> Check<T, PreState> for And<A, B, C>
86where
87    A: Check<T, PreState>,
88    B: Check<T, A::PostState>,
89    C: CombineErrorBuilder<A::Error, B::Error>,
90{
91    type PostState = B::PostState;
92    type Error =  <C::Combiner as CombineError<A::Error, B::Error>>::Out;
93
94    fn check(self, value: CheckState<T, PreState>)
95        -> CheckOutcome<T, Self::PostState, Self::Error>
96    {
97        let mut combine = <C as CombineErrorBuilder<A::Error, B::Error>>::build();
98
99        match self.a.check(value) {
100            CheckOutcome::Passed(v) => {
101                match self.b.check(v){
102                    CheckOutcome::Passed(vv) => {
103                        // success A and success B
104                        CheckOutcome::Passed(vv)
105                    }
106                    CheckOutcome::Failed{state, err} => {
107                        // success A and failed B
108                        combine.right(err);
109                        CheckOutcome::Failed{
110                            state: CheckState { value: state.value, _state: PhantomData },
111                            err: combine.finish()
112                        }
113                    }
114                }
115            }
116            CheckOutcome::Failed{state, err} => {
117                // failed A
118                combine.left(err);
119                CheckOutcome::Failed{
120                    state: CheckState { value: state.value, _state: PhantomData },
121                    err: combine.finish()
122                }
123            }
124        }
125    }
126}
127
128pub struct Or<A, B, C> {
129    a: A,
130    b: B,
131    _combine: PhantomData<C>
132}
133
134impl<T, PreState, A, B, C> Check<T, PreState> for Or<A, B, C>
135where
136    A: Check<T, PreState>,
137    B: Check<T, A::PostState>,
138    C: CombineErrorBuilder<A::Error, B::Error>,
139{
140    type PostState = B::PostState;
141    type Error = C::Out;
142
143    fn check(self, value: CheckState<T, PreState>)
144        -> CheckOutcome<T, Self::PostState, Self::Error>
145    {
146        let mut combine = <C as CombineErrorBuilder<A::Error, B::Error>>::build();
147
148        match self.a.check(value) {
149            CheckOutcome::Passed(v) => {
150                // success A
151                match self.b.check(v) {
152                    CheckOutcome::Passed(vv) => {
153                        // success A and success B
154                        CheckOutcome::Passed(vv)
155                    }
156                    CheckOutcome::Failed{state, err} => {
157                        // success A and failed B
158                        combine.right(err);
159                        CheckOutcome::Failed{
160                            state: CheckState { value: state.value, _state: PhantomData },
161                            err: combine.finish()
162                        }
163                    }
164                }
165            }
166            CheckOutcome::Failed{state, err} => {
167                // failed A
168                combine.left(err);
169                match self.b.check(state) {
170                    CheckOutcome::Passed(vv) => {
171                        // failed A and success B
172                        CheckOutcome::Failed{
173                            state: CheckState { value: vv.value, _state: PhantomData },
174                            err: combine.finish()
175                        }
176                    }
177                    CheckOutcome::Failed{state, err} => {
178                        // failed A and failed B
179                        combine.right(err);
180                        CheckOutcome::Failed{
181                            state: CheckState { value: state.value, _state: PhantomData },
182                            err: combine.finish()
183                        }
184                    }
185                }
186            }
187        }
188    }
189}
190
191impl<T, PreState, PostState, F, E> Check<T, PreState> for F
192where
193    F: Fn(CheckState<T, PreState>) -> CheckOutcome<T, PostState, E>,
194{
195    type PostState = PostState;
196    type Error = E;
197
198    fn check(self, value: CheckState<T, PreState>)
199        -> CheckOutcome<T, Self::PostState, Self::Error>
200    {
201        self(value)
202    }
203}
204
205pub fn check_ref<'a, T: ?Sized, Pre, Post, E, F>(
206    f: F
207) -> impl Check<&'a T, Pre, PostState = Post, Error = E>
208where
209    F: Fn(&T) -> Result<(), E>,
210{
211    move |state: CheckState<&'a T, Pre>| {
212        match f(state.value) {
213            Ok(()) => CheckOutcome::Passed(CheckState::new(state.value)),
214            Err(e) => CheckOutcome::Failed {
215                state: CheckState::new(state.value),
216                err: e,
217            },
218        }
219    }
220}
221
222
223pub fn check_noref<T: Sized, Pre, Post, E, F>( 
224    f: F
225) -> impl Check<T, Pre, PostState = Post, Error = E>
226where 
227    F: Fn(&T) -> Result<(), E>,
228{
229    move |state: CheckState<T, Pre>| {
230          match f(&state.value) {
231             Ok(_v) => {
232                 CheckOutcome::Passed(
233                     CheckState::new(state.value)
234                 )
235             },
236             Err(e) => CheckOutcome::Failed {
237                 state: CheckState::new(state.value),
238                 err: e,
239             },
240         }
241    }
242}