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}