Skip to main content

vld/combinators/
pipe.rs

1use serde_json::Value;
2
3use crate::error::{IssueCode, VldError};
4use crate::schema::VldSchema;
5
6/// Chains two schemas: output of the first is serialized to JSON, then parsed by the second.
7///
8/// Created via [`VldSchema::pipe()`].
9///
10/// # Example
11/// ```
12/// use vld::prelude::*;
13///
14/// // Trim a string, then validate it as a non-negative number.
15/// // The second schema receives a JSON *string*, so it needs `.coerce()`.
16/// let schema = vld::string().trim().pipe(vld::number().coerce().min(0.0));
17/// assert_eq!(schema.parse(r#"" 5 ""#).unwrap(), 5.0);
18/// assert!(schema.parse(r#""-1""#).is_err());
19/// ```
20pub struct ZPipe<A, B>
21where
22    A: VldSchema,
23    B: VldSchema,
24    A::Output: serde::Serialize,
25{
26    first: A,
27    second: B,
28}
29
30impl<A, B> ZPipe<A, B>
31where
32    A: VldSchema,
33    B: VldSchema,
34    A::Output: serde::Serialize,
35{
36    pub fn new(first: A, second: B) -> Self {
37        Self { first, second }
38    }
39
40    /// Access the first (input) stage.
41    pub fn first_schema(&self) -> &A {
42        &self.first
43    }
44
45    /// Access the second (output) stage.
46    pub fn second_schema(&self) -> &B {
47        &self.second
48    }
49}
50
51impl<A, B> VldSchema for ZPipe<A, B>
52where
53    A: VldSchema,
54    B: VldSchema,
55    A::Output: serde::Serialize,
56{
57    type Output = B::Output;
58
59    fn parse_value(&self, value: &Value) -> Result<B::Output, VldError> {
60        let intermediate = self.first.parse_value(value)?;
61        let json = serde_json::to_value(&intermediate).map_err(|e| {
62            VldError::from_code(IssueCode::SerializeError {
63                detail: e.to_string(),
64            })
65        })?;
66        self.second.parse_value(&json)
67    }
68}