Skip to main content

deser_validate/
check.rs

1//! The `Check` adapter.
2use std::borrow::Cow;
3use std::marker::PhantomData;
4
5use deser_core::adapters::{DeserializeAs, Same, SerializeAs};
6use deser_core::de::{OwnedSink, Sink, SinkHandle, checked_update};
7use deser_core::ser::{Chunk, Describe};
8use deser_core::{Atom, ContainerShape, Error, State};
9
10use crate::{Validator, Violation};
11
12/// An adapter that validates values with `V`.
13///
14/// The value is deserialized with the adapter `A` ([`Same`] by default)
15/// and validated once it's complete.  If it's invalid, deserialization
16/// fails with an error that points at the start of the value and has the
17/// [`Violation`](crate::Violation) attached.  The type of the field does
18/// not change, and the adapter composes with the other adapters and the
19/// containers:
20///
21/// ```
22/// use deser::Deserialize;
23/// use deser::adapters::DisplayFromStr;
24/// use deser_validate::{Check, Email, MaxLen, NonEmpty, validator};
25///
26/// validator!(NonZero(port: &u16) => *port != 0, "must not be zero");
27///
28/// #[derive(Deserialize, Debug)]
29/// struct Server {
30///     #[deser(as = Check<NonZero>)]
31///     port: u16,
32///     #[deser(as = Vec<Check<Email>>)]
33///     admins: Vec<String>,
34///     #[deser(as = Option<Check<(NonEmpty, MaxLen<64>)>>)]
35///     name: Option<String>,
36///     // validates the value that `DisplayFromStr` parsed
37///     #[deser(as = Check<NonZero, DisplayFromStr>, default)]
38///     legacy_port: u16,
39/// }
40///
41/// let json = r#"{"port": 0, "admins": []}"#;
42/// let err = deser_json::from_str::<Server>(json).unwrap_err();
43/// assert_eq!(
44///     err.to_string(),
45///     "Unexpected: invalid value: must not be zero at line 1 column 10"
46/// );
47/// let json = r#"{"port": 1, "admins": ["x"]}"#;
48/// let err = deser_json::from_str::<Server>(json).unwrap_err();
49/// assert_eq!(
50///     err.to_string(),
51///     "Unexpected: invalid value: must be an email address \
52///      at line 1 column 24"
53/// );
54/// ```
55///
56/// Values that are missing (see [`DeserializeAs::initial_value_as`]) are
57/// only used if they are valid, otherwise the value is required.
58/// Serialization uses the inner adapter.
59///
60/// # Checks Across Fields
61///
62/// On a type, `Check` wraps its derived implementation (written as `_`).
63/// The validator then sees the whole value:
64///
65/// ```
66/// use deser::Deserialize;
67/// use deser_validate::{Check, validator};
68///
69/// #[derive(Deserialize, Debug)]
70/// #[deser(deserialize_as = Check<OrderedPorts, _>)]
71/// struct PortRange {
72///     min: u16,
73///     max: u16,
74/// }
75///
76/// validator!(
77///     OrderedPorts(range: &PortRange) => range.min <= range.max,
78///     "min is larger than max"
79/// );
80///
81/// let json = r#"{"min": 90, "max": 80}"#;
82/// let err = deser_json::from_str::<PortRange>(json).unwrap_err();
83/// assert_eq!(
84///     err.to_string(),
85///     "Unexpected: invalid value: min is larger than max at line 1 column 1"
86/// );
87/// ```
88///
89/// # Updates
90///
91/// When a value is updated (see
92/// [`Deserialize::deserialize_update`](deser_core::Deserialize::deserialize_update)),
93/// it's updated with `A` and validated once the update is complete.  Types
94/// that update in place (like derived structs) are merged and then
95/// validated as a whole.  If the updated value is invalid, the update fails
96/// but the value keeps the update, like values keep what an update changed
97/// before it failed.
98pub struct Check<V, A = Same>(PhantomData<fn() -> (V, A)>);
99
100impl<'de, T, V, A> DeserializeAs<'de, T> for Check<V, A>
101where
102    T: Send,
103    V: Validator<T> + 'static,
104    A: DeserializeAs<'de, T>,
105{
106    fn deserialize_into_as<'out>(
107        out: &'out mut Option<T>,
108        state: &mut State,
109    ) -> SinkHandle<'out, 'de> {
110        SinkHandle::arena(
111            CheckSink::<T, V> {
112                out,
113                sink: OwnedSink::deserialize_as::<A>(state),
114                start: None,
115                _validator: PhantomData,
116            },
117            state,
118        )
119    }
120
121    fn initial_value_as() -> Option<T> {
122        A::initial_value_as().filter(|value| V::validate(value).is_ok())
123    }
124
125    /// Updates the value with `A` and validates it once the update is
126    /// complete.
127    fn deserialize_update_as<'out>(value: &'out mut T, state: &mut State) -> SinkHandle<'out, 'de>
128    where
129        T: Send,
130    {
131        checked_update(
132            value,
133            A::deserialize_update_as,
134            |value| V::validate(value).map_err(Violation::into_error),
135            state,
136        )
137    }
138
139    #[inline]
140    fn __private_atom_into_as(
141        out: &mut Option<T>,
142        atom: Atom,
143        state: &mut State,
144    ) -> Result<(), Error> {
145        A::__private_atom_into_as(out, atom, state)?;
146        validate_slot::<T, V>(out)
147    }
148
149    #[inline]
150    fn __private_borrowed_atom_into_as(
151        out: &mut Option<T>,
152        atom: Atom<'de>,
153        state: &mut State,
154    ) -> Result<(), Error> {
155        A::__private_borrowed_atom_into_as(out, atom, state)?;
156        validate_slot::<T, V>(out)
157    }
158}
159
160/// Validates the value in a slot, the invalid value is removed.
161///
162/// The error gets the location of the atom from the driver.
163fn validate_slot<T, V: Validator<T>>(slot: &mut Option<T>) -> Result<(), Error> {
164    if let Some(ref value) = *slot
165        && let Err(violation) = V::validate(value)
166    {
167        *slot = None;
168        return Err(violation.into_error());
169    }
170    Ok(())
171}
172
173impl<T: ?Sized, V: 'static, A: SerializeAs<T>> SerializeAs<T> for Check<V, A> {
174    fn serialize_as<'a>(value: &'a T, state: &mut State) -> Result<Chunk<'a>, Error> {
175        A::serialize_as(value, state)
176    }
177
178    fn finish_as(value: &T, state: &mut State) -> Result<(), Error> {
179        A::finish_as(value, state)
180    }
181
182    fn is_optional_as(value: &T) -> bool {
183        A::is_optional_as(value)
184    }
185
186    fn container_shape_as(value: &T) -> ContainerShape {
187        A::container_shape_as(value)
188    }
189
190    fn describe_as(value: &T, d: &mut dyn Describe) {
191        A::describe_as(value, d)
192    }
193}
194
195/// A sink that validates a value once it's complete.
196///
197/// The value is deserialized into an owned sink, validated and moved into
198/// the output.  Errors point at the start of the value.
199struct CheckSink<'a, 'de, T, V> {
200    out: &'a mut Option<T>,
201    sink: OwnedSink<'de, T>,
202    // the start of the value in the input
203    start: Option<usize>,
204    _validator: PhantomData<fn() -> V>,
205}
206
207impl<'a, 'de, T, V> CheckSink<'a, 'de, T, V> {
208    fn begin(&mut self, state: &State) -> &mut (dyn Sink<'de> + '_) {
209        self.start = state.input_range().map(|range| range.start);
210        self.sink.borrow_mut()
211    }
212}
213
214impl<'a, 'de, T: Send, V: Validator<T>> Sink<'de> for CheckSink<'a, 'de, T, V> {
215    fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
216        self.begin(state).atom(atom, state)
217    }
218
219    fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
220        self.begin(state).borrowed_atom(atom, state)
221    }
222
223    fn map(&mut self, state: &mut State) -> Result<(), Error> {
224        self.begin(state).map(state)
225    }
226
227    fn seq(&mut self, state: &mut State) -> Result<(), Error> {
228        self.begin(state).seq(state)
229    }
230
231    fn next_key(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
232        self.sink.borrow_mut().next_key(state)
233    }
234
235    fn next_value(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
236        self.sink.borrow_mut().next_value(state)
237    }
238
239    fn __private_key_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
240        self.sink.borrow_mut().__private_key_atom(atom, state)
241    }
242
243    fn __private_value_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
244        self.sink.borrow_mut().__private_value_atom(atom, state)
245    }
246
247    fn __private_borrowed_key_atom(
248        &mut self,
249        atom: Atom<'de>,
250        state: &mut State,
251    ) -> Result<(), Error> {
252        self.sink
253            .borrow_mut()
254            .__private_borrowed_key_atom(atom, state)
255    }
256
257    fn __private_borrowed_value_atom(
258        &mut self,
259        atom: Atom<'de>,
260        state: &mut State,
261    ) -> Result<(), Error> {
262        self.sink
263            .borrow_mut()
264            .__private_borrowed_value_atom(atom, state)
265    }
266
267    fn value_for_key(
268        &mut self,
269        key: &str,
270        state: &mut State,
271    ) -> Result<Option<SinkHandle<'_, 'de>>, Error> {
272        self.sink.borrow_mut().value_for_key(key, state)
273    }
274
275    fn recover(&mut self, err: Error, state: &mut State) -> Result<(), Error> {
276        self.sink.borrow_mut().recover(err, state)
277    }
278
279    fn finish(&mut self, state: &mut State) -> Result<(), Error> {
280        self.sink.borrow_mut().finish(state)?;
281        if let Some(value) = self.sink.take() {
282            if let Err(violation) = V::validate(&value) {
283                let err = violation.into_error();
284                return Err(match self.start {
285                    Some(start) => err.with_offset(start),
286                    None => err,
287                });
288            }
289            *self.out = Some(value);
290        }
291        Ok(())
292    }
293
294    fn expecting(&self) -> Cow<'_, str> {
295        self.sink.borrow().expecting()
296    }
297}