roadblk_core/
lib.rs

1use lazy_regex::{Lazy, Regex};
2use roadblk_attr::{
3    ConstraintType, EnumError, LengthError, ModelValidatorError, RangeError, RegexError,
4};
5use std::{
6    collections::{HashMap, HashSet},
7    fmt::Display,
8};
9
10pub trait Validator<Data> {
11    type Error;
12
13    // 校验
14    fn validate(data: &Data) -> Result<(), Self::Error>;
15
16    // 约束类型
17    fn constraint_type() -> ConstraintType;
18}
19
20impl<D, T: Validator<D>> Validator<Option<D>> for T {
21    type Error = T::Error;
22
23    fn validate(data: &Option<D>) -> Result<(), Self::Error> {
24        if let Some(data) = data {
25            return T::validate(data);
26        }
27        Ok(())
28    }
29
30    fn constraint_type() -> ConstraintType {
31        T::constraint_type()
32    }
33}
34
35pub trait RegexValidator<V> {
36    fn validate(regex: &Lazy<Regex>, value: &V) -> Result<(), RegexError>;
37}
38
39impl RegexValidator<String> for String {
40    fn validate(regex: &Lazy<Regex>, value: &String) -> Result<(), RegexError> {
41        if regex.is_match(value) {
42            return Ok(());
43        }
44        Err(RegexError {
45            regex: regex.to_string(),
46            value: value.to_string(),
47        })
48    }
49}
50
51impl RegexValidator<Option<String>> for Option<String> {
52    fn validate(regex: &Lazy<Regex>, value: &Option<String>) -> Result<(), RegexError> {
53        if let Some(value) = value {
54            return <String as RegexValidator<String>>::validate(regex, value);
55        }
56        Ok(())
57    }
58}
59
60pub trait RangeValidator {
61    type O: PartialOrd;
62    fn validate(&self, min: Self::O, max: Self::O) -> Result<(), RangeError>;
63}
64
65impl<D: NumberTrait + PartialOrd + Display> RangeValidator for D {
66    type O = D;
67
68    fn validate(&self, min: Self::O, max: Self::O) -> Result<(), RangeError> {
69        if *self < min {
70            return Err(RangeError {
71                min: format!("{min}"),
72                max: format!("{max}"),
73                value: format!("{self}"),
74            });
75        }
76        if *self > max {
77            return Err(RangeError {
78                min: format!("{min}"),
79                max: format!("{max}"),
80                value: format!("{self}"),
81            });
82        }
83        Ok(())
84    }
85}
86
87pub trait NumberTrait {}
88
89impl NumberTrait for i8 {}
90impl NumberTrait for i16 {}
91impl NumberTrait for i32 {}
92impl NumberTrait for i64 {}
93impl NumberTrait for i128 {}
94impl NumberTrait for u8 {}
95impl NumberTrait for usize {}
96impl NumberTrait for u16 {}
97impl NumberTrait for u32 {}
98impl NumberTrait for u64 {}
99impl NumberTrait for u128 {}
100impl NumberTrait for f32 {}
101impl NumberTrait for f64 {}
102
103impl<D: NumberTrait + PartialOrd + Display> RangeValidator for Option<D> {
104    type O = D;
105
106    fn validate(&self, min: Self::O, max: Self::O) -> Result<(), RangeError> {
107        if let Some(data) = self {
108            if *data < min {
109                return Err(RangeError {
110                    min: format!("{min}"),
111                    max: format!("{max}"),
112                    value: format!("{data}"),
113                });
114            }
115            if *data > max {
116                return Err(RangeError {
117                    min: format!("{min}"),
118                    max: format!("{max}"),
119                    value: format!("{data}"),
120                });
121            }
122        }
123        Ok(())
124    }
125}
126
127// 校验器
128pub trait SelfValidator {
129    // 校验
130    fn validate(&self) -> Result<(), ModelValidatorError>;
131}
132
133impl<T: SelfValidator> SelfValidator for Option<T> {
134    fn validate(&self) -> Result<(), ModelValidatorError> {
135        if let Some(data) = self {
136            return data.validate();
137        }
138        Ok(())
139    }
140}
141
142pub trait EnumValidator<'a, T> {
143    fn validate(data: &'a Self) -> Result<(), EnumError>;
144}
145
146impl<'a, T: TryFrom<&'a i32>> EnumValidator<'a, T> for i32 {
147    fn validate(data: &'a Self) -> Result<(), EnumError> {
148        if T::try_from(data).is_err() {
149            return Err(EnumError);
150        }
151        Ok(())
152    }
153}
154
155impl<'a, T: TryFrom<&'a i32>> EnumValidator<'a, T> for Option<i32> {
156    fn validate(data: &'a Self) -> Result<(), EnumError> {
157        if let Some(data) = data {
158            if T::try_from(data).is_err() {
159                return Err(EnumError);
160            }
161        }
162        Ok(())
163    }
164}
165
166impl<'a, T: TryFrom<&'a String>> EnumValidator<'a, T> for String {
167    fn validate(data: &'a Self) -> Result<(), EnumError> {
168        if T::try_from(data).is_err() {
169            return Err(EnumError);
170        }
171        Ok(())
172    }
173}
174
175impl<'a, T: TryFrom<&'a String>> EnumValidator<'a, T> for Option<String> {
176    fn validate(data: &'a Self) -> Result<(), EnumError> {
177        if let Some(data) = data {
178            if T::try_from(data).is_err() {
179                return Err(EnumError);
180            }
181        }
182        Ok(())
183    }
184}
185
186pub trait HasLength {
187    fn length(&self) -> usize;
188}
189
190impl HasLength for String {
191    fn length(&self) -> usize {
192        self.len()
193    }
194}
195
196impl<T> HasLength for Vec<T> {
197    fn length(&self) -> usize {
198        self.len()
199    }
200}
201
202impl<T> HasLength for HashSet<T> {
203    fn length(&self) -> usize {
204        self.len()
205    }
206}
207
208impl<K, V> HasLength for HashMap<K, V> {
209    fn length(&self) -> usize {
210        self.len()
211    }
212}
213
214pub struct LengthValidator<const MIN: usize, const MAX: usize>;
215
216impl<T: HasLength, const MIN: usize, const MAX: usize> Validator<T> for LengthValidator<MIN, MAX> {
217    type Error = LengthError;
218
219    fn validate(data: &T) -> Result<(), Self::Error> {
220        let len = data.length();
221        if len < MIN {
222            return Err(LengthError {
223                min: MIN,
224                max: MAX,
225                len,
226            });
227        }
228        if data.length() > MAX {
229            return Err(LengthError {
230                min: MIN,
231                max: MAX,
232                len,
233            });
234        }
235        Ok(())
236    }
237
238    fn constraint_type() -> ConstraintType {
239        ConstraintType::Length(MIN, MAX)
240    }
241}