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