1use std::ops::Add;
2
3#[derive(Debug, PartialEq)]
4pub struct Error {
5 message: String
6}
7
8impl Error {
9 pub fn get_message(&self) -> String {
10 self.message.clone()
11 }
12}
13
14impl<S: Into<String>> From<S> for Error {
15 fn from(msg: S) -> Self {
16 Error { message: msg.into() }
17 }
18}
19
20
21pub type ValidationResult = Result<(), Error>;
22
23pub struct Rule<T: ? Sized> {
24 rule: Box<Fn(&T) -> ValidationResult>
25}
26
27impl<T: 'static> Rule<T> {
28 pub fn map<'b, F, U>(self, get: F) -> Rule<U>
29 where F: Fn(&U) -> T + 'static,
30 U: ? Sized + 'static {
31 Rule::from(move |input: &U| {
32 let mapped_input = get(input);
33 self.validate(&mapped_input)
34 })
35 }
36}
37
38impl<T: ? Sized + 'static> Rule<T> {
39 pub fn validate(&self, input: &T) -> ValidationResult {
40 (*self.rule)(input)
41 }
42
43 pub fn nest<'b, R, F, U>(get: F, rule: R) -> Self
44 where
45 R: Into<Rule<U>>,
46 F: Fn(&T) -> &U + 'static,
47 U: ? Sized + 'static {
48 let converted_rule = rule.into();
49 Rule::from(move |input: &T| {
50 let mapped_input = get(input);
51 converted_rule.validate(&mapped_input)
52 })
53 }
54
55
56 pub fn name(self, name: &str) -> Self {
57 let name = name.to_owned();
58 Rule::from(move |input: &T| {
59 self.validate(&input).map_err(|err: Error| {
60 (name.clone() + " " + &err.get_message()).into()
61 })
62 })
63 }
64}
65
66impl<T, F> From<F> for Rule<T>
67 where F: Fn(&T) -> ValidationResult + 'static,
68 T: ? Sized {
69 fn from(func: F) -> Self {
70 Rule {
71 rule: Box::new(func)
72 }
73 }
74}
75
76impl<T: ? Sized + 'static, R: Into<Rule<T>>> Add<R> for Rule<T> {
77 type Output = Rule<T>;
78
79 fn add(self, rule: R) -> Self::Output {
80 let rule = rule.into();
81 Rule::from(move |input: &T| {
82 self.validate(input)?;
83 rule.validate(input)
84 })
85 }
86}