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