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 let numeric_regex = Regex::new(r"^-?\d+(?:\.\d+)?$").unwrap();
358 move |value: &Value| {
359 if value.is_null() {
360 return Ok(());
361 }
362
363 if let Value::String(s) = value {
364 let s = s.trim();
365
366 if numeric_regex.is_match(s) {
367 return Ok(());
368 }
369 }
370 Err(ValidationError::NumericError(value.to_string()))
371 }
372 }
373
374 /// Validates common "accepted" terms (true, 1, "yes", "on")
375 ///
376 /// # Example
377 ///
378 /// ```
379 /// use serde_json::json;
380 /// use validate_ro::rules::Rule;
381 ///
382 /// let validator = Rule::accepted();
383 /// assert!(validator.validate(&json!("yes")).is_ok());
384 /// assert!(validator.validate(&json!(true)).is_ok());
385 /// ```
386 pub fn accepted() -> impl Validator {
387 move |value: &Value| {
388 if value.is_null() {
389 return Ok(())
390 }
391 let s = match value {
392 Value::String(s) => s.to_lowercase(),
393 Value::Bool(b) => b.to_string(),
394 Value::Number(n) => n.to_string(),
395 _ => return Err(ValidationError::TypeError {
396 expected: "string, bool, or number".to_string(),
397 got: value.to_string(),
398 }),
399 };
400
401 if matches!(s.as_str(), "yes" | "on" | "1" | "true") {
402 Ok(())
403 } else {
404 Err(ValidationError::AcceptedError(value.to_string()))
405 }
406 }
407 }
408
409 /// Validates that string matches email format
410 ///
411 /// # Arguments
412 ///
413 /// * `allowed_domains` - Optional list of allowed email domains
414 ///
415 /// # Example
416 ///
417 /// ```
418 /// use validate_ro::rules::Rule;
419 ///
420 /// // Only allow @company.com emails
421 /// let validator = Rule::email(Some(vec!["company.com".to_string()]));
422 /// ```
423
424 pub fn email(allowed_domains: Option<Vec<String>>) -> impl Validator {
425 EmailValidator {
426 allowed_domains: allowed_domains.map(|v| v.into_iter().collect()),
427 }
428 }
429
430 /// Validates that value is in allowed set
431 ///
432 /// # Arguments
433 ///
434 /// * `values` - Allowed values
435 ///
436 /// # Example
437 ///
438 /// ```
439 /// use serde_json::json;
440 /// use validate_ro::rules::Rule;
441 ///
442 /// let validator = Rule::in_values(vec![json!("red"), json!("blue")]);
443 /// assert!(validator.validate(&json!("red")).is_ok());
444 /// ```
445 pub fn in_values(values: Vec<Value>) -> impl Validator {
446 InValidator {
447 values
448 }
449 }
450
451
452 /// Validates that value is not in excluded set
453 ///
454 /// # Arguments
455 ///
456 /// * `values` - Excluded values
457 ///
458 /// # Example
459 ///
460 /// ```
461 /// use serde_json::json;
462 /// use validate_ro::rules::Rule;
463 ///
464 /// let validator = Rule::not_in_values(vec![json!("admin")]);
465 /// assert!(validator.validate(&json!("user")).is_ok());
466 /// ```
467 pub fn not_in_values(values: Vec<Value>) -> impl Validator {
468 NotInValidator {
469 values
470 }
471 }
472
473 /// Validates string against regex pattern
474 ///
475 /// # Arguments
476 ///
477 /// * `pattern` - Regex pattern
478 /// * `message` - Optional custom error message
479 ///
480 /// # Example
481 ///
482 /// ```
483 /// use serde_json::json;
484 /// use validate_ro::rules::Rule;
485 ///
486 /// let validator = Rule::regex(r"^\d{3}-\d{3}$", None).unwrap();
487 /// assert!(validator.validate(&json!("123-456")).is_ok());
488 /// ```
489 pub fn regex(pattern: &str, message: Option<String>) -> Result<impl Validator, regex::Error> {
490 Ok(RegexValidator {
491 pattern: Regex::new(pattern)?,
492 message,
493 })
494 }
495
496 /// Validates that value is a valid URL (or null)
497 ///
498 /// # Example
499 ///
500 /// ```
501 /// use serde_json::json;
502 /// use validate_ro::rules::Rule;
503 ///
504 /// let validator = Rule::url();
505 /// assert!(validator.validate(&json!("https://example.com")).is_ok());
506 /// ```
507 pub fn url() -> impl Validator {
508 move |value: &Value| {
509 if value.is_null() {
510 return Ok(())
511 }
512 let s = match value {
513 Value::String(s) => s,
514 _ => return Err(ValidationError::TypeError {
515 expected: "string".to_string(),
516 got: value.to_string(),
517 }),
518 };
519
520 let pattern = r#"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))"#;
521 let re = Regex::new(pattern).unwrap();
522 if re.is_match(s) {
523 Ok(())
524 } else {
525 Err(ValidationError::UrlError(s.clone()))
526 }
527 }
528 }
529
530 /// Validates that value is a valid IP address (or null)
531 ///
532 /// # Example
533 ///
534 /// ```
535 /// use serde_json::json;
536 /// use validate_ro::rules::Rule;
537 ///
538 /// let validator = Rule::ip();
539 /// assert!(validator.validate(&json!("192.168.1.1")).is_ok());
540 /// ```
541 pub fn ip() -> impl Validator {
542 move |value: &Value| {
543 if value.is_null() {
544 return Ok(())
545 }
546 let s = match value {
547 Value::String(s) => s,
548 _ => return Err(ValidationError::TypeError {
549 expected: "string".to_string(),
550 got: value.to_string(),
551 }),
552 };
553
554 let re = Regex::new(r"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$").unwrap();
555 if let Some(caps) = re.captures(s) {
556 if caps.iter().skip(1).all(|m| m.unwrap().as_str().parse::<u8>().is_ok()) {
557 return Ok(());
558 }
559 }
560 Err(ValidationError::IpError(s.clone()))
561 }
562 }
563
564 /// Validates file extension against allowed set
565 ///
566 /// # Arguments
567 ///
568 /// * `allowed` - List of allowed extensions (without dots)
569 ///
570 /// # Example
571 ///
572 /// ```
573 /// use serde_json::json;
574 /// use validate_ro::rules::Rule;
575 ///
576 /// let validator = Rule::extensions(vec!["png".into(), "jpg".into()]);
577 /// assert!(validator.validate(&json!("image.png")).is_ok());
578 /// ```
579 pub fn extensions(allowed: Vec<String>) -> impl Validator {
580 ExtensionValidator {
581 allowed: allowed.into_iter().collect(),
582 }
583 }
584
585 /// Creates custom validator from closure
586 ///
587 /// # Arguments
588 ///
589 /// * `validator` - Validation function
590 ///
591 /// # Example
592 ///
593 /// ```
594 /// use serde_json::json;
595 /// use validate_ro::error::ValidationError;
596 /// use validate_ro::rules::Rule;
597 ///
598 /// let validator = Rule::custom(|value| {
599 /// if value == "secret" {
600 /// Ok(())
601 /// } else {
602 /// Err(ValidationError::Custom("Invalid value".into()))
603 /// }
604 /// });
605 /// ```
606 pub fn custom<F>(validator: F) -> impl Validator
607 where
608 F: Fn(&Value) -> ValidationResult+Send+Sync+ 'static
609 {
610 validator
611 }
612
613 /// Validates field value is unique in MongoDB collection
614 ///
615 /// # Arguments
616 ///
617 /// * `collection` - MongoDB collection name
618 /// * `field` - Field name to check uniqueness
619 /// * `exclude` - Optional document ID to exclude from check (for updates)
620 ///
621 /// # Example
622 ///
623 /// ```rust
624 /// use validate_ro::rules::Rule;
625 ///
626 /// // For new documents:
627 /// let validator = Rule::unique("users", "email", None);
628 ///
629 /// // When updating document:
630 /// let validator = Rule::unique("users", "email", Some(user_id));
631 /// ```
632 pub fn unique(collection: &str, field: &str,exclude:Option<ObjectId>) -> impl Validator {
633 UniqueValidator::new(collection, field,exclude)
634 }
635}
636
637struct UniqueValidator {
638 collection: String,
639 field: String,
640 current_id: Option<ObjectId>,
641}
642
643impl UniqueValidator {
644 pub fn new(collection: &str, field: &str,exclude:Option<ObjectId>) -> Self {
645 Self {
646 collection: collection.to_string(),
647 field: field.to_string(),
648 current_id: exclude,
649 }
650 }
651}
652
653#[async_trait]
654impl Validator for UniqueValidator {
655 fn validate(&self, value: &Value) -> ValidationResult {
656 // This is a placeholder - actual async validation needs to happen in validate_async
657 if value.is_null() {
658 return Ok(());
659 }
660 Err(ValidationError::Custom("Async validation required".to_string()))
661 }
662
663 async fn validate_async(&self, db: &Database, value: &Value) -> ValidationResult {
664 if value.is_null() {
665 return Ok(());
666 }
667
668 let collection: Collection<Document> = db.collection(&self.collection);
669 let field_value = match value {
670 Value::String(s) => Bson::String(s.clone()),
671 Value::Number(n) if n.is_i64() => Bson::Int64(n.as_i64().unwrap()),
672 Value::Number(n) if n.is_f64() => Bson::Double(n.as_f64().unwrap()),
673 _ => return Err(ValidationError::TypeError {
674 expected: "string or number".to_string(),
675 got: value.to_string(),
676 }),
677 };
678
679 let mut filter = doc! { &self.field: field_value };
680
681 if let Some(current_id) = &self.current_id {
682 filter.insert("_id", doc! { "$ne": current_id });
683 }
684
685 match collection.count_documents(filter).await {
686 Ok(count) if count > 0 => {
687 Err(ValidationError::UniqueError)
688 }
689 Ok(_) => Ok(()),
690 Err(_) => {
691 Err(ValidationError::Custom("Database error".to_string()))
692 }
693 }
694 }
695
696 fn as_any(&self) -> &dyn Any {
697 self
698 }
699}
700struct ExtensionValidator {
701 allowed: HashSet<String>,
702}
703
704impl Validator for ExtensionValidator {
705 fn validate(&self, value: &Value) -> ValidationResult {
706 if value.is_null() {
707 return Ok(())
708 }
709 let s = match value {
710 Value::String(s) => s,
711 _ => return Err(ValidationError::TypeError {
712 expected: "string".to_string(),
713 got: value.to_string(),
714 }),
715 };
716
717 if let Some(ext) = s.split('.').last() {
718 if self.allowed.contains(ext) {
719 return Ok(());
720 }
721 }
722 Err(ValidationError::ExtensionError(
723 self.allowed.iter().cloned().collect(),
724 ))
725 }
726
727 fn as_any(&self) -> &dyn Any {
728 self
729 }
730}
731
732
733struct RegexValidator {
734 pattern: Regex,
735 message: Option<String>,
736}
737
738impl Validator for RegexValidator {
739 fn validate(&self, value: &Value) -> ValidationResult {
740 if value.is_null() {
741 return Ok(())
742 }
743 let s = match value {
744 Value::String(s) => s,
745 _ => return Err(ValidationError::TypeError {
746 expected: "string".to_string(),
747 got: value.to_string(),
748 }),
749 };
750
751 if self.pattern.is_match(s) {
752 Ok(())
753 } else {
754 Err(ValidationError::RegexError(
755 self.message.as_ref().map_or(s.clone(), |m| m.clone()),
756 ))
757 }
758 }
759 fn as_any(&self) -> &dyn Any {
760 self
761 }
762}
763
764
765struct NotInValidator {
766 values: Vec<Value>,
767}
768
769impl Validator for NotInValidator {
770 fn validate(&self, value: &Value) -> ValidationResult {
771 if value.is_null() {
772 return Ok(())
773 }
774 if !self.values.contains(value) {
775 return Ok(())
776 }
777 Err(ValidationError::NotInError(format!("{:?}", self.values)))
778 }
779 fn as_any(&self) -> &dyn Any {
780 self
781 }
782}
783
784
785struct InValidator {
786 values: Vec<Value>,
787}
788
789impl Validator for InValidator {
790 fn validate(&self, value: &Value) -> ValidationResult {
791 if value.is_null() {
792 return Ok(())
793 }
794 if self.values.contains(value) {
795 return Ok(())
796 }
797 Err(ValidationError::InError(format!("{:?}", self.values)))
798 }
799 fn as_any(&self) -> &dyn Any {
800 self
801 }
802}
803
804struct EmailValidator {
805 allowed_domains: Option<HashSet<String>>,
806}
807
808impl Validator for EmailValidator {
809 fn validate(&self, value: &Value) -> ValidationResult {
810 if value.is_null() {
811 return Ok(())
812 }
813 let email = match value {
814 Value::String(s) => s,
815 _ => return Err(ValidationError::TypeError {
816 expected: "string".to_string(),
817 got: value.to_string(),
818 }),
819 };
820
821 let parts: Vec<&str> = email.split('@').collect();
822 if parts.len() != 2 {
823 return Err(ValidationError::EmailError(email.clone()));
824 }
825
826 let name = parts[0];
827 let domain = parts[1];
828 let domain_parts: Vec<&str> = domain.split('.').collect();
829
830 if domain_parts.len() < 2 {
831 return Err(ValidationError::EmailError(email.clone()));
832 }
833
834 if domain_parts[1].len() < 2 {
835 return Err(ValidationError::EmailError(email.clone()));
836 }
837
838 if let Some(allowed) = &self.allowed_domains {
839 if !allowed.contains(domain) {
840 return Err(ValidationError::EmailDomainError(domain.to_string()));
841 }
842 }
843
844 if name.len() < 3 {
845 return Err(ValidationError::EmailError(email.clone()));
846 }
847
848 Ok(())
849 }
850 fn as_any(&self) -> &dyn Any {
851 self
852 }
853}
854
855
856
857struct MaxValueValidator {
858 max: f64,
859}
860
861impl Validator for MaxValueValidator {
862 fn validate(&self, value: &Value) -> ValidationResult {
863 if value.is_null() {
864 return Ok(())
865 }
866 let num = match value {
867 Value::Number(n) => n.as_f64().ok_or(ValidationError::TypeError {
868 expected: "number".to_string(),
869 got: value.to_string(),
870 })?,
871 _ => return Err(ValidationError::TypeError {
872 expected: "number".to_string(),
873 got: value.to_string(),
874 }),
875 };
876
877 if num <= self.max {
878 Ok(())
879 } else {
880 Err(ValidationError::MaxValueError {
881 expected: self.max,
882 got: num,
883 })
884 }
885 }
886
887 fn as_any(&self) -> &dyn Any {
888 self
889 }
890}
891
892
893struct MinValueValidator {
894 min: f64,
895}
896
897impl Validator for MinValueValidator {
898 fn validate(&self, value: &Value) -> ValidationResult {
899 if value.is_null() {
900 return Ok(())
901 }
902 let num = match value {
903 Value::Number(n) => n.as_f64().ok_or(ValidationError::TypeError {
904 expected: "number".to_string(),
905 got: value.to_string(),
906 })?,
907 _ => return Err(ValidationError::TypeError {
908 expected: "number".to_string(),
909 got: value.to_string(),
910 }),
911 };
912
913 if num >= self.min {
914 Ok(())
915 } else {
916 Err(ValidationError::MinValueError {
917 expected: self.min,
918 got: num,
919 })
920 }
921 }
922
923 fn as_any(&self) -> &dyn Any {
924 self
925 }
926}
927
928struct EqualValidator {
929 value: Value,
930}
931
932impl Validator for EqualValidator {
933 fn validate(&self, value: &Value) -> ValidationResult {
934 if value.is_null() {
935 return Ok(())
936 }
937 if value == &self.value {
938 Ok(())
939 } else {
940 Err(ValidationError::EqualError {
941 expected: self.value.to_string(),
942 got: value.to_string(),
943 })
944 }
945 }
946
947 fn as_any(&self) -> &dyn Any {
948 self
949 }
950}
951
952struct MaxLengthValidator {
953 max: usize,
954}
955
956impl Validator for MaxLengthValidator {
957 fn validate(&self, value: &Value) -> ValidationResult {
958 if value.is_null() {
959 return Ok(())
960 }
961 let len = match value {
962 Value::String(s) => s.len(),
963 Value::Array(a) => a.len(),
964 Value::Object(o) => o.len(),
965 _ => return Err(ValidationError::TypeError {
966 expected: "string, array, or object".to_string(),
967 got: value.to_string(),
968 }),
969 };
970
971 if len <= self.max {
972 Ok(())
973 } else {
974 Err(ValidationError::MaxLengthError {
975 expected: self.max,
976 got: len,
977 })
978 }
979 }
980
981 fn as_any(&self) -> &dyn Any {
982 self
983 }
984}
985
986
987struct MinLengthValidator {
988 min: usize,
989}
990
991impl Validator for MinLengthValidator {
992 fn validate(&self, value: &Value) -> ValidationResult {
993 if value.is_null() {
994 return Ok(())
995 }
996 let len = match value {
997 Value::String(s) => s.len(),
998 Value::Array(a) => a.len(),
999 Value::Object(o) => o.len(),
1000 _ => return Err(ValidationError::TypeError {
1001 expected: "string, array, or object".to_string(),
1002 got: value.to_string(),
1003 }),
1004 };
1005
1006 if len >= self.min {
1007 Ok(())
1008 } else {
1009 Err(ValidationError::MinLengthError {
1010 expected: self.min,
1011 got: len,
1012 })
1013 }
1014 }
1015
1016 fn as_any(&self) -> &dyn Any {
1017 self
1018 }
1019}
1020
1021
1022struct LengthValidator {
1023 length: usize,
1024}
1025
1026impl Validator for LengthValidator {
1027 fn validate(&self, value: &Value) -> ValidationResult {
1028 if value.is_null() {
1029 return Ok(())
1030 }
1031 let len = match value {
1032 Value::String(s) => s.len(),
1033 Value::Array(a) => a.len(),
1034 Value::Object(o) => o.len(),
1035 _ => return Err(ValidationError::TypeError {
1036 expected: "string, array, or object".to_string(),
1037 got: value.to_string(),
1038 }),
1039 };
1040
1041 if len == self.length {
1042 Ok(())
1043 } else {
1044 Err(ValidationError::LengthError {
1045 expected: self.length,
1046 got: len,
1047 })
1048 }
1049 }
1050
1051 fn as_any(&self) -> &dyn Any {
1052 self
1053 }
1054}