1use std::marker::PhantomData;
2
3use crate::cmberr::{
4 CombineErrorBuilder,
5 CombineError
6};
7
8pub trait Check<T, Pre>
9 where Self:Sized
10{
11 type State;
12 type Error;
13
14 fn check(self, value: CheckState<T, Pre>)
15 -> CheckOutcome<T, Self::State, Self::Error>;
16
17 fn and<B, C>(self, b: B) -> And<Self, B, C>
18 where
19 B: Check<T, Self::State>,
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::State>,
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, Pre, A, B, C> Check<T, Pre> for And<A, B, C>
62where
63 A: Check<T, Pre>,
64 B: Check<T, A::State>,
65 C: CombineErrorBuilder<A::Error, B::Error>,
66{
67 type State = B::State;
68 type Error = <C::Combiner as CombineError<A::Error, B::Error>>::Out;
69
70 fn check(self, value: CheckState<T, Pre>)
71 -> CheckOutcome<T, Self::State, 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 CheckOutcome::Passed(vv)
81 }
82 CheckOutcome::Failed{state, err} => {
83 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 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, Pre, A, B, C> Check<T, Pre> for Or<A, B, C>
111where
112 A: Check<T, Pre>,
113 B: Check<T, A::State>,
114 C: CombineErrorBuilder<A::Error, B::Error>,
115{
116 type State = B::State;
117 type Error = C::Out;
118
119 fn check(self, value: CheckState<T, Pre>)
120 -> CheckOutcome<T, Self::State, 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 match self.b.check(v) {
128 CheckOutcome::Passed(vv) => {
129 CheckOutcome::Passed(vv)
131 }
132 CheckOutcome::Failed{state, err} => {
133 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 combine.left(err);
145 match self.b.check(state) {
146 CheckOutcome::Passed(vv) => {
147 CheckOutcome::Failed{
149 state: CheckState { value: vv.value, _state: PhantomData },
150 err: combine.finish()
151 }
152 }
153 CheckOutcome::Failed{state, err} => {
154 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, Pre, State, F, E> Check<T, Pre> for F
168where
169 F: Fn(CheckState<T, Pre>) -> CheckOutcome<T, State, E>,
170{
171 type State = State;
172 type Error = E;
173
174 fn check(self, value: CheckState<T, Pre>)
175 -> CheckOutcome<T, Self::State, Self::Error>
176 {
177 self(value)
178 }
179}
180