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 CheckOutcome::Passed(vv)
105 }
106 CheckOutcome::Failed{state, err} => {
107 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 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 match self.b.check(v) {
152 CheckOutcome::Passed(vv) => {
153 CheckOutcome::Passed(vv)
155 }
156 CheckOutcome::Failed{state, err} => {
157 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 combine.left(err);
169 match self.b.check(state) {
170 CheckOutcome::Passed(vv) => {
171 CheckOutcome::Failed{
173 state: CheckState { value: vv.value, _state: PhantomData },
174 err: combine.finish()
175 }
176 }
177 CheckOutcome::Failed{state, err} => {
178 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}