icydb_base/validator/
len.rs1#![allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
2
3use crate::{core::traits::Validator, prelude::*};
4use std::{
5 collections::{HashMap, HashSet},
6 hash::BuildHasher,
7};
8
9#[allow(clippy::len_without_is_empty)]
14pub trait HasLen {
15 fn len(&self) -> usize;
16}
17
18impl HasLen for Blob {
19 fn len(&self) -> usize {
20 Self::len(self)
21 }
22}
23
24impl HasLen for str {
25 fn len(&self) -> usize {
26 Self::len(self)
27 }
28}
29
30impl HasLen for String {
31 fn len(&self) -> usize {
32 Self::len(self)
33 }
34}
35
36impl<T> HasLen for [T] {
37 fn len(&self) -> usize {
38 <[T]>::len(self)
39 }
40}
41
42impl<T> HasLen for Vec<T> {
43 fn len(&self) -> usize {
44 Self::len(self)
45 }
46}
47
48impl<T, S: BuildHasher> HasLen for HashSet<T, S> {
49 fn len(&self) -> usize {
50 Self::len(self)
51 }
52}
53
54impl<K, V, S: BuildHasher> HasLen for HashMap<K, V, S> {
55 fn len(&self) -> usize {
56 Self::len(self)
57 }
58}
59
60#[validator]
65pub struct Equal {
66 target: i32,
67}
68
69impl Equal {
70 pub fn new(target: impl Into<i32>) -> Self {
71 let target = target.into();
72 assert!(target >= 0, "equal target must be non-negative");
73
74 Self { target }
75 }
76}
77
78impl<T: HasLen + ?Sized> Validator<T> for Equal {
79 fn validate(&self, t: &T) -> Result<(), String> {
80 let len = t.len() as i32;
81
82 if len == self.target {
83 Ok(())
84 } else {
85 Err(format!("length ({}) is not equal to {}", len, self.target))
86 }
87 }
88}
89
90#[validator]
95pub struct Min {
96 target: i32,
97}
98
99impl Min {
100 pub fn new(target: impl Into<i32>) -> Self {
101 let target = target.into();
102 assert!(target >= 0, "min target must be non-negative");
103
104 Self { target }
105 }
106}
107
108impl<T: HasLen + ?Sized> Validator<T> for Min {
109 fn validate(&self, t: &T) -> Result<(), String> {
110 let len = t.len() as i32;
111
112 if len < self.target {
113 Err(format!(
114 "length ({}) is lower than minimum of {}",
115 len, self.target
116 ))
117 } else {
118 Ok(())
119 }
120 }
121}
122
123#[validator]
128pub struct Max {
129 target: i32,
130}
131
132impl Max {
133 pub fn new(target: impl Into<i32>) -> Self {
134 let target = target.into();
135 assert!(target >= 0, "max target must be non-negative");
136
137 Self { target }
138 }
139}
140
141impl<T: HasLen + ?Sized> Validator<T> for Max {
142 fn validate(&self, t: &T) -> Result<(), String> {
143 let len = t.len() as i32;
144
145 if len > self.target {
146 Err(format!(
147 "length ({}) is greater than maximum of {}",
148 len, self.target
149 ))
150 } else {
151 Ok(())
152 }
153 }
154}
155
156#[validator]
161pub struct Range {
162 min: i32,
163 max: i32,
164}
165
166impl Range {
167 pub fn new(min: impl Into<i32>, max: impl Into<i32>) -> Self {
168 let (min, max) = (min.into(), max.into());
169 assert!(min >= 0, "min target must be non-negative");
170 assert!(max >= 0, "max target must be non-negative");
171 assert!(min <= max, "range requires min <= max");
172
173 Self { min, max }
174 }
175}
176
177impl<T: HasLen + ?Sized> Validator<T> for Range {
178 fn validate(&self, t: &T) -> Result<(), String> {
179 let len = t.len() as i32;
180
181 if len < self.min || len > self.max {
182 Err(format!(
183 "length ({len}) must be between {} and {} (inclusive)",
184 self.min, self.max
185 ))
186 } else {
187 Ok(())
188 }
189 }
190}
191
192#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_range_ok() {
202 let r = Range::new(2, 5);
203 assert!(r.validate("hey").is_ok()); }
205
206 #[test]
207 fn test_range_err() {
208 let r = Range::new(2, 5);
209 assert!(r.validate("hello world").is_err()); }
211}