Skip to main content

vld/combinators/
intersection.rs

1use serde_json::Value;
2
3use crate::error::VldError;
4use crate::schema::VldSchema;
5
6/// Intersection of two schemas: input must satisfy both.
7///
8/// Both schemas are run on the same input. If both succeed, the output of the
9/// **first** schema is returned. If either fails, all errors are merged.
10///
11/// Created via [`vld::intersection()`](crate::intersection).
12///
13/// # Example
14/// ```ignore
15/// let schema = vld::intersection(
16///     vld::string().min(3),
17///     vld::string().email(),
18/// );
19/// ```
20pub struct ZIntersection<A: VldSchema, B: VldSchema> {
21    first: A,
22    second: B,
23}
24
25impl<A: VldSchema, B: VldSchema> ZIntersection<A, B> {
26    /// Create the schema (the same as its `vld::` constructor function).
27    pub fn new(first: A, second: B) -> Self {
28        Self { first, second }
29    }
30
31    /// Access the first schema.
32    pub fn schema_a(&self) -> &A {
33        &self.first
34    }
35    /// Access the second schema.
36    pub fn schema_b(&self) -> &B {
37        &self.second
38    }
39}
40
41impl<A: VldSchema, B: VldSchema> VldSchema for ZIntersection<A, B> {
42    type Output = A::Output;
43
44    fn parse_value(&self, value: &Value) -> Result<A::Output, VldError> {
45        let mut errors = VldError::new();
46        // An inner `Err` may carry no issues: track failure, not issue count.
47        let mut failed = false;
48
49        let first_result = match self.first.parse_value(value) {
50            Ok(v) => Some(v),
51            Err(e) => {
52                failed = true;
53                errors = errors.merge(e);
54                None
55            }
56        };
57
58        if let Err(e) = self.second.parse_value(value) {
59            failed = true;
60            errors = errors.merge(e);
61        }
62
63        match first_result {
64            Some(v) if !failed => Ok(v),
65            _ => Err(errors),
66        }
67    }
68}