type_rules/rules/
eval.rs

1use super::Rule;
2
3/// Rule to constrain any type to a predicate
4///
5/// The value is always passed by its reference
6///
7/// If you pass a closure make sure that the value
8/// are typed, without this, rust consider that your
9/// closure is not general enough because it can't ensure
10/// that it implements FnOnce for any lifetime
11///
12/// # Example
13/// ```
14/// use type_rules::prelude::*;
15///
16/// #[derive(Validator)]
17/// struct EvenInteger(
18///     #[rule(Eval(|v: &u32| v % 2 == 0, "Value need to be even"))]
19///     u32
20/// );
21/// ```
22pub struct Eval<'a, T>(pub T, pub &'a str);
23
24impl<'a, T, U> Rule<U> for Eval<'a, T>
25where
26    T: Fn(&U) -> bool,
27{
28    fn check(&self, value: &U) -> Result<(), String> {
29        match self.0(value) {
30            true => Ok(()),
31            false => Err(String::from(self.1)),
32        }
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use crate::rules::{Eval, Rule};
39    use claim::{assert_err, assert_ok};
40
41    const ERROR_MESSAGE: &str = "Value need to be even";
42    const RULE: Eval<for<'a> fn(&'a u32) -> bool> = Eval(|v| v % 2 == 0, ERROR_MESSAGE);
43
44    #[test]
45    fn eval_ok() {
46        assert_ok!(RULE.check(&2));
47    }
48    #[test]
49    fn eval_err() {
50        assert_err!(RULE.check(&1));
51    }
52    #[test]
53    fn eval_good_error_message() {
54        let res_error_message = RULE.check(&1).expect_err("Should be an Err");
55        assert_eq!(res_error_message, ERROR_MESSAGE);
56    }
57}