type_rules/
valid.rs

1use crate::Validator;
2use std::fmt;
3use std::ops::Deref;
4
5/// `Valid` is a wrapper for any type that implements [`Validator`]
6/// it permit to ensure at compile time that the inner type as been
7/// verified.
8///
9/// With the [`serde`] feature, Valid can be serialized and deserialized
10/// with validity check.
11/// ```
12/// use type_rules::prelude::*;
13///
14/// #[derive(Validator)]
15/// struct NewUser {
16///     #[rule(MinMaxLength(3, 50))]
17///     username: String,
18///     #[rule(MinMaxLength(8, 100))]
19///     password: String,
20/// }
21///
22/// fn do_something(user: Valid<NewUser>) {
23///     // No need to check if user is valid
24/// }
25///
26/// let new_user = NewUser {
27///     username: "example".to_string(),
28///     password: "OPw$5%hJJ".to_string(),
29/// };
30/// do_something(Valid::new(new_user).unwrap());
31/// ```
32#[derive(Debug)]
33pub struct Valid<T: Validator>(T);
34
35impl<T: Validator> Valid<T> {
36    #[allow(dead_code)]
37    pub fn new(val: T) -> Result<Self, String> {
38        val.check_validity()?;
39        Ok(Valid(val))
40    }
41
42    #[allow(dead_code)]
43    pub fn into_inner(self) -> T {
44        self.0
45    }
46}
47
48impl<T: Validator> Deref for Valid<T> {
49    type Target = T;
50
51    fn deref(&self) -> &Self::Target {
52        &self.0
53    }
54}
55
56impl<T: Validator + fmt::Display> fmt::Display for Valid<T> {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        fmt::Display::fmt(&self.0, f)
59    }
60}
61
62#[cfg(feature = "serde")]
63#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
64impl<'a, T: Validator + serde::Deserialize<'a>> serde::Deserialize<'a> for Valid<T> {
65    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
66    where
67        D: serde::Deserializer<'a>,
68    {
69        let v = T::deserialize(deserializer)?;
70        Valid::new(v).map_err(serde::de::Error::custom)
71    }
72}
73
74#[cfg(feature = "serde")]
75#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
76impl<T: Validator + serde::Serialize> serde::Serialize for Valid<T> {
77    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
78    where
79        S: serde::Serializer,
80    {
81        self.0.serialize(serializer)
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use crate::valid::Valid;
88    use crate::Validator;
89    use claim::{assert_err, assert_ok};
90
91    #[derive(Debug)]
92    struct ValidTest(i32);
93
94    impl Validator for ValidTest {
95        fn check_validity(&self) -> Result<(), String> {
96            match self.0.is_positive() {
97                true => Ok(()),
98                false => Err(String::from("Need to be positive")),
99            }
100        }
101    }
102
103    #[test]
104    fn valid_ok() {
105        assert_ok!(Valid::new(ValidTest(1)));
106    }
107
108    #[test]
109    fn valid_err() {
110        assert_err!(Valid::new(ValidTest(-1)));
111    }
112
113    #[cfg(feature = "serde")]
114    mod serde_tests {
115        use crate::valid::Valid;
116        use crate::Validator;
117        use claim::{assert_err, assert_ok};
118        use serde_derive::{Deserialize, Serialize};
119
120        #[derive(Deserialize, Serialize, Debug)]
121        struct Int {
122            val: i32,
123        }
124
125        impl Validator for Int {
126            fn check_validity(&self) -> Result<(), String> {
127                match self.val.is_positive() {
128                    true => Ok(()),
129                    false => Err(String::from("Need to be positive")),
130                }
131            }
132        }
133
134        #[test]
135        fn valid_serde_ok() {
136            let serialized = "{\"val\":1}";
137            let res: serde_json::Result<Valid<Int>> = serde_json::from_str(serialized);
138            assert_ok!(res);
139        }
140
141        #[test]
142        fn valid_serde_err() {
143            let serialized = "{\"val\":-1}";
144            let res: serde_json::Result<Valid<Int>> = serde_json::from_str(serialized);
145            assert_err!(res);
146        }
147
148        #[test]
149        fn valid_serde_serialize() {
150            let valid_int = Valid::new(Int { val: 1 }).unwrap();
151            let serialized = serde_json::to_string(&valid_int).unwrap();
152            assert_eq!(&serialized, "{\"val\":1}")
153        }
154    }
155}