validate/
rule.rs

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}