1use std::collections::LinkedList;
2use semigroup::Semigroup;
3
4#[derive(Clone, Debug)]
5pub enum Validation<E, A> {
6 Success(A),
7 Failure(E),
8}
9
10pub fn success<E: Clone, A: Clone>(item: A) -> Validation<E, A> {
11 Validation::Success(item)
12}
13
14pub fn failure<E: Clone, A: Clone>(e: E) -> Validation<E, A> {
15 Validation::Failure(e)
16}
17
18impl<E: Clone + Semigroup, A: Clone> Validation<E, A> {
19 pub fn map<B, F>(&self, f: F) -> Validation<E, B>
42 where
43 F: FnOnce(A) -> B,
44 {
45 match self {
46 &Validation::Success(ref a) => Validation::Success(f(a.clone())),
47 &Validation::Failure(ref e) => Validation::Failure::<E, B>(e.clone()),
48 }
49 }
50
51 pub fn get_or_else(self, fallback: A) -> A {
52 match self {
53 Validation::Success(a) => a,
54 Validation::Failure(_) => fallback,
55 }
56 }
57
58 pub fn unwrap(self) -> A {
59 match self {
60 Validation::Success(a) => a,
61 Validation::Failure(_) => panic!("Validation is a failure"),
62 }
63 }
64 pub fn is_success(&self) -> bool {
65 match self {
66 &Validation::Success(_) => true,
67 &Validation::Failure(_) => false,
68 }
69 }
70 pub fn is_failure(&self) -> bool {
71 !self.is_success()
72 }
73
74 pub fn get_err(self) -> E {
75 match self {
76 Validation::Failure(e) => e,
77 Validation::Success(_) => panic!("Validation is a success"),
78 }
79 }
80}
81
82fn collect_err1<A, E>(a: Validation<E, A>, e: E) -> E
83where
84 A: Clone,
85 E: Clone + Semigroup,
86{
87 match a {
88 Validation::Failure(x) => x.mappend(e),
89 Validation::Success(_) => e,
90 }
91}
92fn collect_err2<A, B, E>(a: Validation<E, A>, b: Validation<E, B>, e: E) -> E
93where
94 A: Clone,
95 B: Clone,
96 E: Clone + Semigroup,
97{
98 match b {
99 Validation::Failure(x) => x.mappend(collect_err1(a, e)),
100 Validation::Success(_) => collect_err1(a, e),
101 }
102}
103fn collect_err3<A, B, C, E>(
104 a: Validation<E, A>,
105 b: Validation<E, B>,
106 c: Validation<E, C>,
107 e: E,
108) -> E
109where
110 A: Clone,
111 B: Clone,
112 C: Clone,
113 E: Clone + Semigroup,
114{
115 match c {
116 Validation::Failure(x) => x.mappend(collect_err2(a, b, e)),
117 Validation::Success(_) => collect_err2(a, b, e),
118 }
119}
120
121fn collect_err4<A, B, C, D, E>(
122 a: Validation<E, A>,
123 b: Validation<E, B>,
124 c: Validation<E, C>,
125 d: Validation<E, D>,
126 e: E,
127) -> E
128where
129 A: Clone,
130 B: Clone,
131 C: Clone,
132 D: Clone,
133 E: Clone + Semigroup,
134{
135 match d {
136 Validation::Failure(x) => x.mappend(collect_err3(a, b, c, e)),
137 Validation::Success(_) => collect_err3(a, b, c, e),
138 }
139}
140
141pub fn apply2<A, B, R, F, E>(a: Validation<E, A>, b: Validation<E, B>, f: F) -> Validation<E, R>
144where
145 A: Clone,
146 B: Clone,
147 R: Clone,
148 E: Clone + Semigroup,
149 F: FnOnce(A, B) -> R,
150{
151
152 match b {
153 Validation::Failure(e) => Validation::Failure(collect_err1(a, e)),
154 Validation::Success(b2) => {
155 let p = |a2: A| f(a2, b2);
156 a.map(p)
157 }
158 }
159}
160
161pub fn apply3<A, B, C, R, F, E>(
166 a: Validation<E, A>,
167 b: Validation<E, B>,
168 c: Validation<E, C>,
169 f: F,
170) -> Validation<E, R>
171where
172 A: Clone,
173 B: Clone,
174 C: Clone,
175 R: Clone,
176 E: Clone + Semigroup,
177 F: FnOnce(A, B, C) -> R,
178{
179
180 match c {
181 Validation::Failure(e) => Validation::Failure(collect_err2(a, b, e)),
182 Validation::Success(c2) => {
183 let p = |a2: A, b2: B| f(a2, b2, c2);
184 apply2(a, b, p)
185 }
186 }
187}
188pub fn apply4<A, B, C, D, R, F, E>(
193 a: Validation<E, A>,
194 b: Validation<E, B>,
195 c: Validation<E, C>,
196 d: Validation<E, D>,
197 f: F,
198) -> Validation<E, R>
199where
200 A: Clone,
201 B: Clone,
202 C: Clone,
203 D: Clone,
204 R: Clone,
205 E: Clone + Semigroup,
206 F: FnOnce(A, B, C, D) -> R,
207{
208
209 match d {
210 Validation::Failure(e) => Validation::Failure(collect_err3(a, b, c, e)),
211 Validation::Success(d2) => {
212 let p = |a2: A, b2: B, c2: C| f(a2, b2, c2, d2);
213 apply3(a, b, c, p)
214 }
215 }
216}
217pub fn apply5<A, B, C, D, G, R, F, E>(
222 a: Validation<E, A>,
223 b: Validation<E, B>,
224 c: Validation<E, C>,
225 d: Validation<E, D>,
226 g: Validation<E, G>,
227 f: F,
228) -> Validation<E, R>
229where
230 A: Clone,
231 B: Clone,
232 C: Clone,
233 D: Clone,
234 G: Clone,
235 R: Clone,
236 E: Clone + Semigroup,
237 F: FnOnce(A, B, C, D, G) -> R,
238{
239
240 match g {
241 Validation::Failure(e) => Validation::Failure(collect_err4(a, b, c, d, e)),
242 Validation::Success(g2) => {
243 let p = |a2: A, b2: B, c2: C, d2: D| f(a2, b2, c2, d2, g2);
244 apply4(a, b, c, d, p)
245 }
246 }
247}
248
249impl<T: Clone> Semigroup for LinkedList<T> {
250 fn mappend(&self, b: LinkedList<T>) -> LinkedList<T> {
251 let mut cloned_list = self.clone();
252 for e in b.iter() {
253 cloned_list.push_back(e.clone());
254 }
255 cloned_list
256 }
257}
258
259pub type ValidationNel<E: Clone, A: Clone> = Validation<LinkedList<E>, A>;
260
261pub fn failure_nel<E: Clone, A: Clone>(e: E) -> ValidationNel<E, A> {
262 let mut li: LinkedList<E> = LinkedList::new();
263 li.push_back(e);
264 Validation::Failure(li)
265}
266
267pub fn success_nel<E: Clone, A: Clone>(a: A) -> ValidationNel<E, A> {
268 Validation::Success(a)
269}
270
271#[cfg(test)]
272mod tests {
273 use validation::*;
274 use super::success;
275 use super::failure;
276
277 impl Semigroup for i32 {
279 fn mappend(&self, b: i32) -> i32 {
280 self + b
281 }
282 }
283
284
285 fn add2(a: i32, b: i32) -> i32 {
287 a + b
288 }
289 fn add3(a: i32, b: i32, c: i32) -> i32 {
291 a + b + c
292 }
293
294 fn div(s: i32, t: i32) -> ValidationNel<String, i32> {
297 match t {
298 0 => failure_nel::<String, i32>("Cannot devide by 0".to_owned()),
299 _ => success_nel::<String, i32>(s / t),
300 }
301 }
302
303 #[test]
304 fn it_works() {
305 let a = success::<i32, i32>(1);
306 let b = success::<i32, i32>(2);
307 let r = apply2(a, b, add2);
308 assert!(r.unwrap() == 3);
309
310 let a = success::<i32, i32>(1);
311 let b = success::<i32, i32>(2);
312 let c = success::<i32, i32>(3);
313 let r = apply3(a, b, c, add3);
314 assert!(r.unwrap() == 6);
315
316 let a = success::<i32, i32>(1);
317 let b = success::<i32, i32>(2);
318 let e = failure::<i32, i32>(3);
319 let r = apply3(a, b, e, add3);
320 assert!(r.is_failure());
321
322 let r = div(10, 0);
323 assert!(r.is_failure());
324
325 let r = div(10, 2);
326 assert!(r.unwrap() == 5);
327
328 let r = apply3(div(10, 0), div(10, 1), div(0, 0), add3);
329 assert!(r.get_err().len() == 2);
330
331 let r = apply3(
332 failure::<i32, i32>(1),
333 failure::<i32, i32>(1),
334 failure::<i32, i32>(1),
335 add3,
336 );
337 assert!(r.get_err() == 3);
338 }
339
340}