Skip to main content

vld/combinators/
refine.rs

1use serde_json::Value;
2
3use crate::error::{IssueCode, VldError};
4use crate::schema::VldSchema;
5
6/// Adds a custom refinement check to a schema without changing its output type.
7///
8/// Created via [`VldSchema::refine()`].
9///
10/// # Example
11/// ```
12/// use vld::prelude::*;
13///
14/// let even = vld::number().int().refine(|n| n % 2 == 0, "Must be even");
15/// ```
16pub struct ZRefine<T, F>
17where
18    T: VldSchema,
19    F: Fn(&T::Output) -> bool,
20{
21    inner: T,
22    check: F,
23    message: String,
24}
25
26impl<T, F> ZRefine<T, F>
27where
28    T: VldSchema,
29    F: Fn(&T::Output) -> bool,
30{
31    /// Create the schema (the same as its `vld::` constructor function).
32    pub fn new(inner: T, check: F, message: &str) -> Self {
33        Self {
34            inner,
35            check,
36            message: message.to_string(),
37        }
38    }
39
40    /// Access the inner schema.
41    pub fn inner_schema(&self) -> &T {
42        &self.inner
43    }
44}
45
46impl<T, F> VldSchema for ZRefine<T, F>
47where
48    T: VldSchema,
49    F: Fn(&T::Output) -> bool,
50{
51    type Output = T::Output;
52
53    fn parse_value(&self, value: &Value) -> Result<T::Output, VldError> {
54        let result = self.inner.parse_value(value)?;
55
56        if (self.check)(&result) {
57            Ok(result)
58        } else {
59            Err(VldError::single(
60                IssueCode::Custom {
61                    code: "custom".to_string(),
62                },
63                self.message.clone(),
64            ))
65        }
66    }
67    fn output_json(&self, o: &Self::Output) -> Option<Value> {
68        self.inner.output_json(o)
69    }
70}