type_rules/rules/
regex.rs

1use super::Rule;
2use regex::Regex;
3
4/// Rule to constraint any type that implements [`AsRef<str>`] such
5/// as [`String`] or `&str` to match a Regex
6///
7/// You need the `regex` feature to use it
8///
9/// # Example
10/// ```
11/// use type_rules::prelude::*;
12///
13/// #[derive(Validator)]
14/// struct Mail(#[rule(RegEx(r"^\S+@\S+\.\S+"))] String);
15/// ```
16pub struct RegEx<'a>(pub &'a str);
17
18impl<'a, T: AsRef<str> + ?Sized> Rule<T> for RegEx<'a> {
19    fn check(&self, value: &T) -> Result<(), String> {
20        check(self.0, value.as_ref())
21    }
22}
23
24fn check(regex: &str, value: &str) -> Result<(), String> {
25    let regex = Regex::new(regex).expect("Invalid Regex");
26    if regex.is_match(value) {
27        return Ok(());
28    }
29    Err(String::from("The regex does not match"))
30}
31
32#[cfg(test)]
33mod tests {
34    use crate::rules::{RegEx, Rule};
35    use claim::{assert_err, assert_ok};
36
37    #[test]
38    fn regex_ok() {
39        assert_ok!(RegEx(r"^\S+@\S+\.\S+").check("example@example.fr"));
40    }
41    #[test]
42    fn regex_err() {
43        assert_err!(RegEx(r"^\S+@\S+\.\S+").check("exampleexample.fr"));
44    }
45}