Skip to main content

vld/combinators/
super_refine.rs

1use serde_json::Value;
2
3use crate::error::VldError;
4use crate::schema::VldSchema;
5
6/// Refinement that can produce multiple errors at once.
7///
8/// Created via [`VldSchema::super_refine()`].
9///
10/// # Example
11/// ```
12/// use vld::prelude::*;
13///
14/// let schema = vld::string().super_refine(|s, errors| {
15///     if s.len() < 3 {
16///         errors.push(IssueCode::Custom { code: "too_short".into() }, "Too short");
17///     }
18///     if !s.contains('@') {
19///         errors.push(IssueCode::Custom { code: "no_at".into() }, "Missing @");
20///     }
21/// });
22/// ```
23pub struct ZSuperRefine<T, F>
24where
25    T: VldSchema,
26    F: Fn(&T::Output, &mut VldError),
27{
28    inner: T,
29    check: F,
30}
31
32impl<T, F> ZSuperRefine<T, F>
33where
34    T: VldSchema,
35    F: Fn(&T::Output, &mut VldError),
36{
37    /// Create the schema (the same as its `vld::` constructor function).
38    pub fn new(inner: T, check: F) -> Self {
39        Self { inner, check }
40    }
41
42    /// Access the inner schema (for nested OpenAPI component collection).
43    pub fn inner_schema(&self) -> &T {
44        &self.inner
45    }
46}
47
48impl<T, F> VldSchema for ZSuperRefine<T, F>
49where
50    T: VldSchema,
51    F: Fn(&T::Output, &mut VldError),
52{
53    type Output = T::Output;
54
55    fn parse_value(&self, value: &Value) -> Result<T::Output, VldError> {
56        let result = self.inner.parse_value(value)?;
57        let mut errors = VldError::new();
58        (self.check)(&result, &mut errors);
59        if errors.is_empty() {
60            Ok(result)
61        } else {
62            Err(errors)
63        }
64    }
65    fn output_json(&self, o: &Self::Output) -> Option<Value> {
66        self.inner.output_json(o)
67    }
68}