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
42pub struct CheckState<T: Sized, S> 
43    where Self: Sized 
44{
45    pub value: T,
46    _state: PhantomData<S>
47}
48
49impl<T, S> CheckState<T, S> {
50    pub fn new(value: T) -> Self {
51        Self { value, _state: PhantomData }
52    }
53}
54
55pub struct And<A, B, C> {
56    a: A,
57    b: B,
58    _combine: PhantomData<C>
59}
60
61impl<T, PreState, A, B, C> Check<T, PreState> for And<A, B, C>
62where
63    A: Check<T, PreState>,
64    B: Check<T, A::PostState>,
65    C: CombineErrorBuilder<A::Error, B::Error>,
66{
67    type PostState = B::PostState;
68    type Error =  <C::Combiner as CombineError<A::Error, B::Error>>::Out;
69
70    fn check(self, value: CheckState<T, PreState>)
71        -> CheckOutcome<T, Self::PostState, Self::Error>
72    {
73        let mut combine = <C as CombineErrorBuilder<A::Error, B::Error>>::build();
74
75        match self.a.check(value) {
76            CheckOutcome::Passed(v) => {
77                match self.b.check(v){
78                    CheckOutcome::Passed(vv) => {
79                        // success A and success B
80                        CheckOutcome::Passed(vv)
81                    }
82                    CheckOutcome::Failed{state, err} => {
83                        // success A and failed B
84                        combine.right(err);
85                        CheckOutcome::Failed{
86                            state: CheckState { value: state.value, _state: PhantomData },
87                            err: combine.finish()
88                        }
89                    }
90                }
91            }
92            CheckOutcome::Failed{state, err} => {
93                // failed A
94                combine.left(err);
95                CheckOutcome::Failed{
96                    state: CheckState { value: state.value, _state: PhantomData },
97                    err: combine.finish()
98                }
99            }
100        }
101    }
102}
103
104pub struct Or<A, B, C> {
105    a: A,
106    b: B,
107    _combine: PhantomData<C>
108}
109
110impl<T, PreState, A, B, C> Check<T, PreState> for Or<A, B, C>
111where
112    A: Check<T, PreState>,
113    B: Check<T, A::PostState>,
114    C: CombineErrorBuilder<A::Error, B::Error>,
115{
116    type PostState = B::PostState;
117    type Error = C::Out;
118
119    fn check(self, value: CheckState<T, PreState>)
120        -> CheckOutcome<T, Self::PostState, Self::Error>
121    {
122        let mut combine = <C as CombineErrorBuilder<A::Error, B::Error>>::build();
123
124        match self.a.check(value) {
125            CheckOutcome::Passed(v) => {
126                // success A
127                match self.b.check(v) {
128                    CheckOutcome::Passed(vv) => {
129                        // success A and success B
130                        CheckOutcome::Passed(vv)
131                    }
132                    CheckOutcome::Failed{state, err} => {
133                        // success A and failed B
134                        combine.right(err);
135                        CheckOutcome::Failed{
136                            state: CheckState { value: state.value, _state: PhantomData },
137                            err: combine.finish()
138                        }
139                    }
140                }
141            }
142            CheckOutcome::Failed{state, err} => {
143                // failed A
144                combine.left(err);
145                match self.b.check(state) {
146                    CheckOutcome::Passed(vv) => {
147                        // failed A and success B
148                        CheckOutcome::Failed{
149                            state: CheckState { value: vv.value, _state: PhantomData },
150                            err: combine.finish()
151                        }
152                    }
153                    CheckOutcome::Failed{state, err} => {
154                        // failed A and failed B
155                        combine.right(err);
156                        CheckOutcome::Failed{
157                            state: CheckState { value: state.value, _state: PhantomData },
158                            err: combine.finish()
159                        }
160                    }
161                }
162            }
163        }
164    }
165}
166
167impl<T, PreState, PostState, F, E> Check<T, PreState> for F
168where
169    F: Fn(CheckState<T, PreState>) -> CheckOutcome<T, PostState, E>,
170{
171    type PostState = PostState;
172    type Error = E;
173
174    fn check(self, value: CheckState<T, PreState>)
175        -> CheckOutcome<T, Self::PostState, Self::Error>
176    {
177        self(value)
178    }
179}
180
181pub fn check_ref<'a, T: ?Sized, Pre, Post, E, F>(
182    f: F
183) -> impl Check<&'a T, Pre, PostState = Post, Error = E>
184where
185    F: Fn(&T) -> Result<(), E>,
186{
187    move |state: CheckState<&'a T, Pre>| {
188        match f(state.value) {
189            Ok(()) => CheckOutcome::Passed(CheckState::new(state.value)),
190            Err(e) => CheckOutcome::Failed {
191                state: CheckState::new(state.value),
192                err: e,
193            },
194        }
195    }
196}
197
198
199pub fn check_noref<T: Sized, Pre, Post, E, F>( 
200    f: F
201) -> impl Check<T, Pre, PostState = Post, Error = E>
202where 
203    F: Fn(&T) -> Result<(), E>,
204{
205    move |state: CheckState<T, Pre>| {
206          match f(&state.value) {
207             Ok(_v) => {
208                 CheckOutcome::Passed(
209                     CheckState::new(state.value)
210                 )
211             },
212             Err(e) => CheckOutcome::Failed {
213                 state: CheckState::new(state.value),
214                 err: e,
215             },
216         }
217    }
218}