validate_ro/rules.rs
1//! # Built-in Validation Rules
2//!
3//! Provides common validation rules ready to use:
4//!
5//! ## Basic Type Validation
6//! - `required()` - Value must not be null
7//! - `string()` - Value must be a string
8//! - `integer()` - Value must be an integer
9//! - `float()` - Value must be a float
10//! - `boolean()` - Value must be a boolean
11//! - `array()` - Value must be an array
12//! - `object()` - Value must be an object
13//!
14//! ## String Validation
15//! - `length(n)` - Exact length
16//! - `min_length(n)` - Minimum length
17//! - `max_length(n)` - Maximum length
18//! - `email()` - Valid email format
19//! - `url()` - Valid URL format
20//! - `ip()` - Valid IP address
21//! - `regex()` - Matches regex pattern
22//!
23//! ## Numeric Validation
24//! - `min_value(n)` - Minimum numeric value
25//! - `max_value(n)` - Maximum numeric value
26//! - `equal(n)` - Exact value match
27//!
28//! ## Collection Validation
29//! - `in_values()` - Value must be in allowed set
30//! - `not_in_values()` - Value must not be in excluded set
31//!
32//! ## Database Validation
33//! - `unique()` - Field value must be unique in MongoDB collection
34//!
35//! ## Custom Validation
36//! - `custom()` - Implement custom validation logic
37
38use std::any::Any;
39use std::collections::HashSet;
40use std::sync::Arc;
41use async_trait::async_trait;
42use mongodb::bson::{doc, Bson, Document};
43use mongodb::{Collection, Database};
44use mongodb::bson::oid::ObjectId;
45use regex::Regex;
46use serde_json::Value;
47use crate::error::ValidationError;
48use crate::traits::{ValidationResult, Validator};
49
50/// Factory for creating validation rules
51pub struct Rule;
52impl Rule {
53 /// Validates that value is not null
54 ///
55 /// # Example
56 ///
57 /// ```
58 /// use validate_ro::rules::Rule;
59 ///
60 /// let validator = Rule::required();
61 /// ```
62 pub fn required() -> impl Validator {
63 move |value: &Value| {
64 if value.is_null() {
65 Err(ValidationError::Required)
66 } else {
67 Ok(())
68 }
69 }
70 }
71
72 /// Validates that value is a string (or null)
73 pub fn string() -> impl Validator {
74 move |value: &Value| {
75 if value.is_null() {
76 return Ok(())
77 }
78 if !value.is_string() {
79 Err(ValidationError::TypeError {
80 expected: "string".to_string(),
81 got: value.to_string()
82 })
83 } else {
84 Ok(())
85 }
86 }
87 }
88
89 /// Validates that value is an array (or null)
90 ///
91 /// # Example
92 ///
93 /// ```
94 /// use serde_json::json;
95 /// use validate_ro::rules::Rule;
96 ///
97 /// let validator = Rule::array();
98 /// assert!(validator.validate(&json!([1, 2, 3])).is_ok());
99 /// ```
100 pub fn array() -> impl Validator {
101 move |value: &Value| {
102 if value.is_null() {
103 return Ok(())
104 }
105 if !value.is_array() {
106 Err(ValidationError::TypeError {
107 expected: "array".to_string(),
108 got: value.to_string()
109 })
110 } else {
111 Ok(())
112 }
113 }
114 }
115
116 /// Validates that value is an object (or null)
117 ///
118 /// # Example
119 ///
120 /// ```
121 /// use serde_json::json;
122 /// use validate_ro::rules::Rule;
123 ///
124 /// let validator = Rule::object();
125 /// assert!(validator.validate(&json!({"key": "value"})).is_ok());
126 /// ```
127 pub fn object() -> impl Validator {
128 move |value: &Value| {
129 if value.is_null() {
130 return Ok(())
131 }
132 if !value.is_object() {
133 Err(ValidationError::TypeError {
134 expected: "object".to_string(),
135 got: value.to_string()
136 })
137 } else {
138 Ok(())
139 }
140 }
141 }
142
143 /// Validates that value is a boolean (or null)
144 ///
145 /// # Example
146 ///
147 /// ```
148 /// use serde_json::json;
149 /// use validate_ro::rules::Rule;
150 ///
151 /// let validator = Rule::boolean();
152 /// assert!(validator.validate(&json!(true)).is_ok());
153 /// ```
154 pub fn boolean() -> impl Validator {
155 move |value: &Value| {
156 if value.is_null() {
157 return Ok(())
158 }
159 if !value.is_boolean() {
160 Err(ValidationError::TypeError {
161 expected: "bool".to_string(),
162 got: value.to_string()
163 })
164 } else {
165 Ok(())
166 }
167 }
168 }
169
170 /// Validates that value is a float number (or null)
171 ///
172 /// # Example
173 ///
174 /// ```
175 /// use serde_json::json;
176 /// use validate_ro::rules::Rule;
177 ///
178 /// let validator = Rule::float();
179 /// assert!(validator.validate(&json!(3.14)).is_ok());
180 /// ```
181 pub fn float() -> impl Validator {
182 move |value: &Value| {
183 if value.is_null() {
184 return Ok(())
185 }
186 if !value.is_f64() {
187 Err(ValidationError::TypeError {
188 expected: "float".to_string(),
189 got: value.to_string()
190 })
191 } else {
192 Ok(())
193 }
194 }
195 }
196
197 /// Validates that value is an integer (or null)
198 ///
199 /// # Example
200 ///
201 /// ```
202 /// use serde_json::json;
203 /// use validate_ro::rules::Rule;
204 ///
205 /// let validator = Rule::integer();
206 /// assert!(validator.validate(&json!(42)).is_ok());
207 /// ```
208 pub fn integer() -> impl Validator {
209 move |value: &Value| {
210 if value.is_null() {
211 return Ok(())
212 }
213 if !value.is_i64() {
214 Err(ValidationError::TypeError {
215 expected: "int".to_string(),
216 got: value.to_string()
217 })
218 } else {
219 Ok(())
220 }
221 }
222 }
223
224
225 /// Validates exact length for strings/arrays/objects
226 ///
227 /// # Arguments
228 ///
229 /// * `len` - Exact required length
230 ///
231 /// # Example
232 ///
233 /// ```
234 /// use serde_json::json;
235 /// use validate_ro::rules::Rule;
236 ///
237 /// let validator = Rule::length(3);
238 /// assert!(validator.validate(&json!("abc")).is_ok());
239 /// assert!(validator.validate(&json!([1, 2, 3])).is_ok());
240 /// ```
241 pub fn length(len: usize) -> impl Validator {
242 LengthValidator { length: len }
243 }
244
245
246 /// Validates minimum length for strings/arrays/objects
247 ///
248 /// # Arguments
249 ///
250 /// * `min` - Minimum allowed length
251 ///
252 /// # Example
253 ///
254 /// ```
255 /// use serde_json::json;
256 /// use validate_ro::rules::Rule;
257 ///
258 /// let validator = Rule::min_length(5);
259 /// assert!(validator.validate(&json!("long enough")).is_ok());
260 /// ```
261 pub fn min_length(min: usize) -> impl Validator {
262 MinLengthValidator { min }
263 }
264
265
266 /// Validates maximum length for strings/arrays/objects
267 ///
268 /// # Arguments
269 ///
270 /// * `max` - Maximum allowed length
271 ///
272 /// # Example
273 ///
274 /// ```
275 /// use serde_json::json;
276 /// use validate_ro::rules::Rule;
277 ///
278 /// let validator = Rule::max_length(10);
279 /// assert!(validator.validate(&json!("short")).is_ok());
280 /// ```
281 pub fn max_length(max: usize) -> impl Validator {
282 MaxLengthValidator { max }
283 }
284
285
286 /// Validates exact value match
287 ///
288 /// # Arguments
289 ///
290 /// * `value` - Expected value to match against
291 ///
292 /// # Example
293 ///
294 /// ```
295 /// use serde_json::json;
296 /// use validate_ro::rules::Rule;
297 ///
298 /// let validator = Rule::equal(json!("expected"));
299 /// assert!(validator.validate(&json!("expected")).is_ok());
300 /// ```
301 pub fn equal(value: Value) -> impl Validator {
302 EqualValidator { value }
303 }
304
305
306 /// Validates minimum numeric value
307 ///
308 /// # Arguments
309 ///
310 /// * `min` - Minimum allowed value
311 ///
312 /// # Example
313 ///
314 /// ```
315 /// use serde_json::json;
316 /// use validate_ro::rules::Rule;
317 ///
318 /// let validator = Rule::min_value(18.0);
319 /// assert!(validator.validate(&json!(21)).is_ok());
320 /// ```
321 pub fn min_value(min: f64) -> impl Validator {
322 MinValueValidator { min }
323 }
324
325
326 /// Validates maximum numeric value
327 ///
328 /// # Arguments
329 ///
330 /// * `max` - Maximum allowed value
331 ///
332 /// # Example
333 ///
334 /// ```
335 /// use serde_json::json;
336 /// use validate_ro::rules::Rule;
337 ///
338 /// let validator = Rule::max_value(100.0);
339 /// assert!(validator.validate(&json!(75)).is_ok());
340 /// ```
341 pub fn max_value(max: f64) -> impl Validator {
342 MaxValueValidator { max }
343 }
344
345
346 /// Validates that string can be parsed as number (or null)
347 ///
348 /// # Example
349 ///
350 /// ```
351 /// use serde_json::json;
352 /// use validate_ro::rules::Rule;
353 ///
354 /// let validator = Rule::numeric();
355 /// assert!(validator.validate(&json!("123.45")).is_ok());
356 /// ```
357 pub fn numeric() -> impl Validator {
358 move |value: &Value| {
359 if value.is_null() {
360 return Ok(())
361 }
362 if let Value::String(s) = value {
363 if s.parse::<f64>().is_ok() {
364 return Ok(());
365 }
366 }
367 Err(ValidationError::NumericError(value.to_string()))
368 }
369 }
370
371 /// Validates common "accepted" terms (true, 1, "yes", "on")
372 ///
373 /// # Example
374 ///
375 /// ```
376 /// use serde_json::json;
377 /// use validate_ro::rules::Rule;
378 ///
379 /// let validator = Rule::accepted();
380 /// assert!(validator.validate(&json!("yes")).is_ok());
381 /// assert!(validator.validate(&json!(true)).is_ok());
382 /// ```
383 pub fn accepted() -> impl Validator {
384 move |value: &Value| {
385 if value.is_null() {
386 return Ok(())
387 }
388 let s = match value {
389 Value::String(s) => s.to_lowercase(),
390 Value::Bool(b) => b.to_string(),
391 Value::Number(n) => n.to_string(),
392 _ => return Err(ValidationError::TypeError {
393 expected: "string, bool, or number".to_string(),
394 got: value.to_string(),
395 }),
396 };
397
398 if matches!(s.as_str(), "yes" | "on" | "1" | "true") {
399 Ok(())
400 } else {
401 Err(ValidationError::AcceptedError(value.to_string()))
402 }
403 }
404 }
405
406 /// Validates that string matches email format
407 ///
408 /// # Arguments
409 ///
410 /// * `allowed_domains` - Optional list of allowed email domains
411 ///
412 /// # Example
413 ///
414 /// ```
415 /// use validate_ro::rules::Rule;
416 ///
417 /// // Only allow @company.com emails
418 /// let validator = Rule::email(Some(vec!["company.com".to_string()]));
419 /// ```
420
421 pub fn email(allowed_domains: Option<Vec<String>>) -> impl Validator {
422 EmailValidator {
423 allowed_domains: allowed_domains.map(|v| v.into_iter().collect()),
424 }
425 }
426
427 /// Validates that value is in allowed set
428 ///
429 /// # Arguments
430 ///
431 /// * `values` - Allowed values
432 ///
433 /// # Example
434 ///
435 /// ```
436 /// use serde_json::json;
437 /// use validate_ro::rules::Rule;
438 ///
439 /// let validator = Rule::in_values(vec![json!("red"), json!("blue")]);
440 /// assert!(validator.validate(&json!("red")).is_ok());
441 /// ```
442 pub fn in_values(values: Vec<Value>) -> impl Validator {
443 InValidator {
444 values
445 }
446 }
447
448
449 /// Validates that value is not in excluded set
450 ///
451 /// # Arguments
452 ///
453 /// * `values` - Excluded values
454 ///
455 /// # Example
456 ///
457 /// ```
458 /// use serde_json::json;
459 /// use validate_ro::rules::Rule;
460 ///
461 /// let validator = Rule::not_in_values(vec![json!("admin")]);
462 /// assert!(validator.validate(&json!("user")).is_ok());
463 /// ```
464 pub fn not_in_values(values: Vec<Value>) -> impl Validator {
465 NotInValidator {
466 values
467 }
468 }
469
470 /// Validates string against regex pattern
471 ///
472 /// # Arguments
473 ///
474 /// * `pattern` - Regex pattern
475 /// * `message` - Optional custom error message
476 ///
477 /// # Example
478 ///
479 /// ```
480 /// use serde_json::json;
481 /// use validate_ro::rules::Rule;
482 ///
483 /// let validator = Rule::regex(r"^\d{3}-\d{3}$", None).unwrap();
484 /// assert!(validator.validate(&json!("123-456")).is_ok());
485 /// ```
486 pub fn regex(pattern: &str, message: Option<String>) -> Result<impl Validator, regex::Error> {
487 Ok(RegexValidator {
488 pattern: Regex::new(pattern)?,
489 message,
490 })
491 }
492
493 /// Validates that value is a valid URL (or null)
494 ///
495 /// # Example
496 ///
497 /// ```
498 /// use serde_json::json;
499 /// use validate_ro::rules::Rule;
500 ///
501 /// let validator = Rule::url();
502 /// assert!(validator.validate(&json!("https://example.com")).is_ok());
503 /// ```
504 pub fn url() -> impl Validator {
505 move |value: &Value| {
506 if value.is_null() {
507 return Ok(())
508 }
509 let s = match value {
510 Value::String(s) => s,
511 _ => return Err(ValidationError::TypeError {
512 expected: "string".to_string(),
513 got: value.to_string(),
514 }),
515 };
516
517 let pattern = r#"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))"#;
518 let re = Regex::new(pattern).unwrap();
519 if re.is_match(s) {
520 Ok(())
521 } else {
522 Err(ValidationError::UrlError(s.clone()))
523 }
524 }
525 }
526
527 /// Validates that value is a valid IP address (or null)
528 ///
529 /// # Example
530 ///
531 /// ```
532 /// use serde_json::json;
533 /// use validate_ro::rules::Rule;
534 ///
535 /// let validator = Rule::ip();
536 /// assert!(validator.validate(&json!("192.168.1.1")).is_ok());
537 /// ```
538 pub fn ip() -> impl Validator {
539 move |value: &Value| {
540 if value.is_null() {
541 return Ok(())
542 }
543 let s = match value {
544 Value::String(s) => s,
545 _ => return Err(ValidationError::TypeError {
546 expected: "string".to_string(),
547 got: value.to_string(),
548 }),
549 };
550
551 let re = Regex::new(r"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$").unwrap();
552 if let Some(caps) = re.captures(s) {
553 if caps.iter().skip(1).all(|m| m.unwrap().as_str().parse::<u8>().is_ok()) {
554 return Ok(());
555 }
556 }
557 Err(ValidationError::IpError(s.clone()))
558 }
559 }
560
561 /// Validates file extension against allowed set
562 ///
563 /// # Arguments
564 ///
565 /// * `allowed` - List of allowed extensions (without dots)
566 ///
567 /// # Example
568 ///
569 /// ```
570 /// use serde_json::json;
571 /// use validate_ro::rules::Rule;
572 ///
573 /// let validator = Rule::extensions(vec!["png".into(), "jpg".into()]);
574 /// assert!(validator.validate(&json!("image.png")).is_ok());
575 /// ```
576 pub fn extensions(allowed: Vec<String>) -> impl Validator {
577 ExtensionValidator {
578 allowed: allowed.into_iter().collect(),
579 }
580 }
581
582 /// Creates custom validator from closure
583 ///
584 /// # Arguments
585 ///
586 /// * `validator` - Validation function
587 ///
588 /// # Example
589 ///
590 /// ```
591 /// use serde_json::json;
592 /// use validate_ro::error::ValidationError;
593 /// use validate_ro::rules::Rule;
594 ///
595 /// let validator = Rule::custom(|value| {
596 /// if value == "secret" {
597 /// Ok(())
598 /// } else {
599 /// Err(ValidationError::Custom("Invalid value".into()))
600 /// }
601 /// });
602 /// ```
603 pub fn custom<F>(validator: F) -> impl Validator
604 where
605 F: Fn(&Value) -> ValidationResult+Send+Sync+ 'static
606 {
607 validator
608 }
609
610 /// Validates field value is unique in MongoDB collection
611 ///
612 /// # Arguments
613 ///
614 /// * `collection` - MongoDB collection name
615 /// * `field` - Field name to check uniqueness
616 /// * `exclude` - Optional document ID to exclude from check (for updates)
617 ///
618 /// # Example
619 ///
620 /// ```rust
621 /// use validate_ro::rules::Rule;
622 ///
623 /// // For new documents:
624 /// let validator = Rule::unique("users", "email", None);
625 ///
626 /// // When updating document:
627 /// let validator = Rule::unique("users", "email", Some(user_id));
628 /// ```
629 pub fn unique(collection: &str, field: &str,exclude:Option<ObjectId>) -> impl Validator {
630 UniqueValidator::new(collection, field,exclude)
631 }
632}
633
634struct UniqueValidator {
635 collection: String,
636 field: String,
637 current_id: Option<ObjectId>,
638}
639
640impl UniqueValidator {
641 pub fn new(collection: &str, field: &str,exclude:Option<ObjectId>) -> Self {
642 Self {
643 collection: collection.to_string(),
644 field: field.to_string(),
645 current_id: exclude,
646 }
647 }
648}
649
650#[async_trait]
651impl Validator for UniqueValidator {
652 fn validate(&self, value: &Value) -> ValidationResult {
653 // This is a placeholder - actual async validation needs to happen in validate_async
654 if value.is_null() {
655 return Ok(());
656 }
657 Err(ValidationError::Custom("Async validation required".to_string()))
658 }
659
660 async fn validate_async(&self, db: &Arc<Database>, value: &Value) -> ValidationResult {
661 if value.is_null() {
662 return Ok(());
663 }
664
665 let collection: Collection<Document> = db.collection(&self.collection);
666 let field_value = match value {
667 Value::String(s) => Bson::String(s.clone()),
668 Value::Number(n) if n.is_i64() => Bson::Int64(n.as_i64().unwrap()),
669 Value::Number(n) if n.is_f64() => Bson::Double(n.as_f64().unwrap()),
670 _ => return Err(ValidationError::TypeError {
671 expected: "string or number".to_string(),
672 got: value.to_string(),
673 }),
674 };
675
676 let mut filter = doc! { &self.field: field_value };
677
678 if let Some(current_id) = &self.current_id {
679 filter.insert("_id", doc! { "$ne": current_id });
680 }
681
682 match collection.count_documents(filter).await {
683 Ok(count) if count > 0 => {
684 Err(ValidationError::UniqueError)
685 }
686 Ok(_) => Ok(()),
687 Err(_) => {
688 Err(ValidationError::Custom("Database error".to_string()))
689 }
690 }
691 }
692
693 fn as_any(&self) -> &dyn Any {
694 self
695 }
696}
697struct ExtensionValidator {
698 allowed: HashSet<String>,
699}
700
701impl Validator for ExtensionValidator {
702 fn validate(&self, value: &Value) -> ValidationResult {
703 if value.is_null() {
704 return Ok(())
705 }
706 let s = match value {
707 Value::String(s) => s,
708 _ => return Err(ValidationError::TypeError {
709 expected: "string".to_string(),
710 got: value.to_string(),
711 }),
712 };
713
714 if let Some(ext) = s.split('.').last() {
715 if self.allowed.contains(ext) {
716 return Ok(());
717 }
718 }
719 Err(ValidationError::ExtensionError(
720 self.allowed.iter().cloned().collect(),
721 ))
722 }
723
724 fn as_any(&self) -> &dyn Any {
725 self
726 }
727}
728
729
730struct RegexValidator {
731 pattern: Regex,
732 message: Option<String>,
733}
734
735impl Validator for RegexValidator {
736 fn validate(&self, value: &Value) -> ValidationResult {
737 if value.is_null() {
738 return Ok(())
739 }
740 let s = match value {
741 Value::String(s) => s,
742 _ => return Err(ValidationError::TypeError {
743 expected: "string".to_string(),
744 got: value.to_string(),
745 }),
746 };
747
748 if self.pattern.is_match(s) {
749 Ok(())
750 } else {
751 Err(ValidationError::RegexError(
752 self.message.as_ref().map_or(s.clone(), |m| m.clone()),
753 ))
754 }
755 }
756 fn as_any(&self) -> &dyn Any {
757 self
758 }
759}
760
761
762struct NotInValidator {
763 values: Vec<Value>,
764}
765
766impl Validator for NotInValidator {
767 fn validate(&self, value: &Value) -> ValidationResult {
768 if value.is_null() {
769 return Ok(())
770 }
771 if !self.values.contains(value) {
772 return Ok(())
773 }
774 Err(ValidationError::NotInError(format!("{:?}", self.values)))
775 }
776 fn as_any(&self) -> &dyn Any {
777 self
778 }
779}
780
781
782struct InValidator {
783 values: Vec<Value>,
784}
785
786impl Validator for InValidator {
787 fn validate(&self, value: &Value) -> ValidationResult {
788 if value.is_null() {
789 return Ok(())
790 }
791 if self.values.contains(value) {
792 return Ok(())
793 }
794 Err(ValidationError::InError(format!("{:?}", self.values)))
795 }
796 fn as_any(&self) -> &dyn Any {
797 self
798 }
799}
800
801struct EmailValidator {
802 allowed_domains: Option<HashSet<String>>,
803}
804
805impl Validator for EmailValidator {
806 fn validate(&self, value: &Value) -> ValidationResult {
807 if value.is_null() {
808 return Ok(())
809 }
810 let email = match value {
811 Value::String(s) => s,
812 _ => return Err(ValidationError::TypeError {
813 expected: "string".to_string(),
814 got: value.to_string(),
815 }),
816 };
817
818 let parts: Vec<&str> = email.split('@').collect();
819 if parts.len() != 2 {
820 return Err(ValidationError::EmailError(email.clone()));
821 }
822
823 let name = parts[0];
824 let domain = parts[1];
825 let domain_parts: Vec<&str> = domain.split('.').collect();
826
827 if domain_parts.len() < 2 {
828 return Err(ValidationError::EmailError(email.clone()));
829 }
830
831 if domain_parts[1].len() < 2 {
832 return Err(ValidationError::EmailError(email.clone()));
833 }
834
835 if let Some(allowed) = &self.allowed_domains {
836 if !allowed.contains(domain) {
837 return Err(ValidationError::EmailDomainError(domain.to_string()));
838 }
839 }
840
841 if name.len() < 3 {
842 return Err(ValidationError::EmailError(email.clone()));
843 }
844
845 Ok(())
846 }
847 fn as_any(&self) -> &dyn Any {
848 self
849 }
850}
851
852
853
854struct MaxValueValidator {
855 max: f64,
856}
857
858impl Validator for MaxValueValidator {
859 fn validate(&self, value: &Value) -> ValidationResult {
860 if value.is_null() {
861 return Ok(())
862 }
863 let num = match value {
864 Value::Number(n) => n.as_f64().ok_or(ValidationError::TypeError {
865 expected: "number".to_string(),
866 got: value.to_string(),
867 })?,
868 _ => return Err(ValidationError::TypeError {
869 expected: "number".to_string(),
870 got: value.to_string(),
871 }),
872 };
873
874 if num <= self.max {
875 Ok(())
876 } else {
877 Err(ValidationError::MaxValueError {
878 expected: self.max,
879 got: num,
880 })
881 }
882 }
883
884 fn as_any(&self) -> &dyn Any {
885 self
886 }
887}
888
889
890struct MinValueValidator {
891 min: f64,
892}
893
894impl Validator for MinValueValidator {
895 fn validate(&self, value: &Value) -> ValidationResult {
896 if value.is_null() {
897 return Ok(())
898 }
899 let num = match value {
900 Value::Number(n) => n.as_f64().ok_or(ValidationError::TypeError {
901 expected: "number".to_string(),
902 got: value.to_string(),
903 })?,
904 _ => return Err(ValidationError::TypeError {
905 expected: "number".to_string(),
906 got: value.to_string(),
907 }),
908 };
909
910 if num >= self.min {
911 Ok(())
912 } else {
913 Err(ValidationError::MinValueError {
914 expected: self.min,
915 got: num,
916 })
917 }
918 }
919
920 fn as_any(&self) -> &dyn Any {
921 self
922 }
923}
924
925struct EqualValidator {
926 value: Value,
927}
928
929impl Validator for EqualValidator {
930 fn validate(&self, value: &Value) -> ValidationResult {
931 if value.is_null() {
932 return Ok(())
933 }
934 if value == &self.value {
935 Ok(())
936 } else {
937 Err(ValidationError::EqualError {
938 expected: self.value.to_string(),
939 got: value.to_string(),
940 })
941 }
942 }
943
944 fn as_any(&self) -> &dyn Any {
945 self
946 }
947}
948
949struct MaxLengthValidator {
950 max: usize,
951}
952
953impl Validator for MaxLengthValidator {
954 fn validate(&self, value: &Value) -> ValidationResult {
955 if value.is_null() {
956 return Ok(())
957 }
958 let len = match value {
959 Value::String(s) => s.len(),
960 Value::Array(a) => a.len(),
961 Value::Object(o) => o.len(),
962 _ => return Err(ValidationError::TypeError {
963 expected: "string, array, or object".to_string(),
964 got: value.to_string(),
965 }),
966 };
967
968 if len <= self.max {
969 Ok(())
970 } else {
971 Err(ValidationError::MaxLengthError {
972 expected: self.max,
973 got: len,
974 })
975 }
976 }
977
978 fn as_any(&self) -> &dyn Any {
979 self
980 }
981}
982
983
984struct MinLengthValidator {
985 min: usize,
986}
987
988impl Validator for MinLengthValidator {
989 fn validate(&self, value: &Value) -> ValidationResult {
990 if value.is_null() {
991 return Ok(())
992 }
993 let len = match value {
994 Value::String(s) => s.len(),
995 Value::Array(a) => a.len(),
996 Value::Object(o) => o.len(),
997 _ => return Err(ValidationError::TypeError {
998 expected: "string, array, or object".to_string(),
999 got: value.to_string(),
1000 }),
1001 };
1002
1003 if len >= self.min {
1004 Ok(())
1005 } else {
1006 Err(ValidationError::MinLengthError {
1007 expected: self.min,
1008 got: len,
1009 })
1010 }
1011 }
1012
1013 fn as_any(&self) -> &dyn Any {
1014 self
1015 }
1016}
1017
1018
1019struct LengthValidator {
1020 length: usize,
1021}
1022
1023impl Validator for LengthValidator {
1024 fn validate(&self, value: &Value) -> ValidationResult {
1025 if value.is_null() {
1026 return Ok(())
1027 }
1028 let len = match value {
1029 Value::String(s) => s.len(),
1030 Value::Array(a) => a.len(),
1031 Value::Object(o) => o.len(),
1032 _ => return Err(ValidationError::TypeError {
1033 expected: "string, array, or object".to_string(),
1034 got: value.to_string(),
1035 }),
1036 };
1037
1038 if len == self.length {
1039 Ok(())
1040 } else {
1041 Err(ValidationError::LengthError {
1042 expected: self.length,
1043 got: len,
1044 })
1045 }
1046 }
1047
1048 fn as_any(&self) -> &dyn Any {
1049 self
1050 }
1051}