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::Same;
6use deser_core::de::{OwnedSink, Sink, SinkHandle, checked_update};
7use deser_core::ser::{Describe, Emit};
8use deser_core::{Atom, ContainerShape, Deserialize, Error, Serialize, 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`] 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///     "InvalidValue: 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///     "InvalidValue: invalid value: must be an email address \
52///      at line 1 column 24"
53/// );
54/// ```
55///
56/// Values that are missing (see [`Deserialize::initial_value`]) 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///     "InvalidValue: 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`]),
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> Deserialize<'de, T> for Check<V, A>
101where
102    T: Send,
103    V: Validator<T> + 'static,
104    A: Deserialize<'de, T>,
105{
106    fn deserialize_into<'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 expecting() -> Cow<'static, str> {
122        A::expecting()
123    }
124
125    fn describe_type(d: &mut dyn Describe) {
126        A::describe_type(d)
127    }
128
129    fn initial_value() -> Option<T> {
130        A::initial_value().filter(|value| V::validate(value).is_ok())
131    }
132
133    /// Updates the value with `A` and validates it once the update is
134    /// complete.
135    fn deserialize_update<'out>(value: &'out mut T, state: &mut State) -> SinkHandle<'out, 'de> {
136        checked_update(
137            value,
138            A::deserialize_update,
139            |value| V::validate(value).map_err(Violation::into_error),
140            state,
141        )
142    }
143
144    #[inline]
145    fn __private_atom_into(
146        out: &mut Option<T>,
147        atom: Atom,
148        state: &mut State,
149    ) -> Result<(), Error> {
150        A::__private_atom_into(out, atom, state)?;
151        validate_slot::<T, V>(out)
152    }
153
154    #[inline]
155    fn __private_borrowed_atom_into(
156        out: &mut Option<T>,
157        atom: Atom<'de>,
158        state: &mut State,
159    ) -> Result<(), Error> {
160        A::__private_borrowed_atom_into(out, atom, state)?;
161        validate_slot::<T, V>(out)
162    }
163}
164
165/// Validates the value in a slot, the invalid value is removed.
166///
167/// The error gets the location of the atom from the driver.
168fn validate_slot<T, V: Validator<T>>(slot: &mut Option<T>) -> Result<(), Error> {
169    if let Some(ref value) = *slot
170        && let Err(violation) = V::validate(value)
171    {
172        *slot = None;
173        return Err(violation.into_error());
174    }
175    Ok(())
176}
177
178impl<T: ?Sized, V: 'static, A: Serialize<T>> Serialize<T> for Check<V, A> {
179    fn serialize<'a>(value: &'a T, state: &mut State) -> Result<Emit<'a>, Error> {
180        A::serialize(value, state)
181    }
182
183    fn finish(value: &T, state: &mut State) -> Result<(), Error> {
184        A::finish(value, state)
185    }
186
187    fn is_optional(value: &T) -> bool {
188        A::is_optional(value)
189    }
190
191    fn container_shape(value: &T) -> ContainerShape {
192        A::container_shape(value)
193    }
194
195    fn describe(value: &T, d: &mut dyn Describe) {
196        A::describe(value, d)
197    }
198}
199
200/// A sink that validates a value once it's complete.
201///
202/// The value is deserialized into an owned sink, validated and moved into
203/// the output.  Errors point at the start of the value.
204struct CheckSink<'a, 'de, T, V> {
205    out: &'a mut Option<T>,
206    sink: OwnedSink<'de, T>,
207    // the start of the value in the input
208    start: Option<usize>,
209    _validator: PhantomData<fn() -> V>,
210}
211
212impl<'a, 'de, T, V> CheckSink<'a, 'de, T, V> {
213    fn begin(&mut self, state: &State) -> &mut (dyn Sink<'de> + '_) {
214        self.start = state.input_range().map(|range| range.start);
215        self.sink.get_mut()
216    }
217}
218
219impl<'a, 'de, T: Send, V: Validator<T>> Sink<'de> for CheckSink<'a, 'de, T, V> {
220    fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
221        self.begin(state).atom(atom, state)
222    }
223
224    fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
225        self.begin(state).borrowed_atom(atom, state)
226    }
227
228    fn map(&mut self, state: &mut State) -> Result<(), Error> {
229        self.begin(state).map(state)
230    }
231
232    fn seq(&mut self, state: &mut State) -> Result<(), Error> {
233        self.begin(state).seq(state)
234    }
235
236    fn next_key(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
237        self.sink.get_mut().next_key(state)
238    }
239
240    fn next_value(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
241        self.sink.get_mut().next_value(state)
242    }
243
244    fn __private_key_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
245        self.sink.get_mut().__private_key_atom(atom, state)
246    }
247
248    fn __private_value_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
249        self.sink.get_mut().__private_value_atom(atom, state)
250    }
251
252    fn __private_borrowed_key_atom(
253        &mut self,
254        atom: Atom<'de>,
255        state: &mut State,
256    ) -> Result<(), Error> {
257        self.sink.get_mut().__private_borrowed_key_atom(atom, state)
258    }
259
260    fn __private_borrowed_value_atom(
261        &mut self,
262        atom: Atom<'de>,
263        state: &mut State,
264    ) -> Result<(), Error> {
265        self.sink
266            .get_mut()
267            .__private_borrowed_value_atom(atom, state)
268    }
269
270    fn value_for_key(
271        &mut self,
272        key: &str,
273        state: &mut State,
274    ) -> Result<Option<SinkHandle<'_, 'de>>, Error> {
275        self.sink.get_mut().value_for_key(key, state)
276    }
277
278    fn recover(&mut self, err: Error, state: &mut State) -> Result<(), Error> {
279        self.sink.get_mut().recover(err, state)
280    }
281
282    fn finish(&mut self, state: &mut State) -> Result<(), Error> {
283        self.sink.get_mut().finish(state)?;
284        if let Some(value) = self.sink.take() {
285            if let Err(violation) = V::validate(&value) {
286                let mut err = violation.into_error();
287                if let Some(start) = self.start {
288                    err.set_offset(start);
289                }
290                return Err(err);
291            }
292            *self.out = Some(value);
293        }
294        Ok(())
295    }
296
297    fn expecting(&self) -> Cow<'_, str> {
298        self.sink.get().expecting()
299    }
300}