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}