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 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, 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 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, 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}