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}