Skip to main content

deser_core/de/
collect.rs

1//! Support for collecting the errors of items (see
2//! [`State::set_collect_errors`]).
3use crate::State;
4use crate::error::Error;
5
6/// Collects the errors of a whole deserialization (a value of the
7/// [`Context`](crate::Context)).
8///
9/// With this in the context, maps and sequences collect the errors of their
10/// items and deserialization continues to find the other errors (see
11/// [`State::set_collect_errors`]).  The limit of errors is optional:
12///
13/// ```
14/// use deser::de::CollectErrors;
15/// use deser::Context;
16///
17/// let config = deser_json::DeserializerConfig::builder()
18///     .context(Context::with(CollectErrors::with_max_errors(10)))
19///     .build();
20/// let err = config.from_str::<Vec<u32>>(r#"["a", 1, true]"#).unwrap_err();
21/// assert_eq!(err.errors().count(), 2);
22/// ```
23#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
24pub struct CollectErrors {
25    pub(crate) max: Option<usize>,
26}
27
28impl CollectErrors {
29    /// Collects errors without limit.
30    pub const fn new() -> CollectErrors {
31        CollectErrors { max: None }
32    }
33
34    /// Collects errors up to a limit (see [`set_max_errors`](Self::set_max_errors)).
35    pub const fn with_max_errors(max: usize) -> CollectErrors {
36        CollectErrors { max: Some(max) }
37    }
38
39    /// Limits the number of errors that are collected (see
40    /// [`State::set_max_errors`]).
41    pub const fn set_max_errors(&mut self, max: usize) {
42        self.max = Some(max);
43    }
44
45    /// Returns the limit of errors (see [`set_max_errors`](Self::set_max_errors)).
46    pub const fn max_errors(&self) -> Option<usize> {
47        self.max
48    }
49}
50
51/// The errors a map or sequence collected from its items.
52///
53/// This is a helper for sinks that collect the errors of their items (see
54/// [`State::set_collect_errors`]).  In [`Sink::recover`](crate::de::Sink::recover)
55/// the error is passed to [`collect`](Self::collect), which keeps it if
56/// errors are collected.  Once the container is complete,
57/// [`finish`](Self::finish) fails with all errors that were collected:
58///
59/// ```
60/// use deser::de::{CollectedErrors, Deserialize, Sink, SinkHandle};
61/// use deser::{Error, State};
62///
63/// struct Numbers(Vec<u32>);
64///
65/// struct NumbersSink<'a> {
66///     out: &'a mut Option<Numbers>,
67///     numbers: Vec<u32>,
68///     current: Option<u32>,
69///     errors: CollectedErrors,
70/// }
71///
72/// impl<'a> NumbersSink<'a> {
73///     fn flush(&mut self) {
74///         self.numbers.extend(self.current.take());
75///     }
76/// }
77///
78/// impl<'de> Sink<'de> for NumbersSink<'_> {
79///     fn seq(&mut self, _state: &mut State) -> Result<(), Error> {
80///         Ok(())
81///     }
82///
83///     fn next_value(
84///         &mut self,
85///         state: &mut State,
86///     ) -> Result<SinkHandle<'_, 'de>, Error> {
87///         self.flush();
88///         Ok(u32::deserialize_into(&mut self.current, state))
89///     }
90///
91///     fn recover(
92///         &mut self,
93///         err: Error,
94///         state: &mut State,
95///     ) -> Result<(), Error> {
96///         self.current = None;
97///         self.errors.collect(err, state)
98///     }
99///
100///     fn finish(&mut self, _state: &mut State) -> Result<(), Error> {
101///         self.errors.finish()?;
102///         self.flush();
103///         *self.out = Some(Numbers(std::mem::take(&mut self.numbers)));
104///         Ok(())
105///     }
106/// }
107/// ```
108#[derive(Debug, Default)]
109pub struct CollectedErrors {
110    // a single pointer as every container sink holds this, it's an error
111    // that holds multiple errors once there are more
112    errors: Option<Error>,
113}
114
115impl CollectedErrors {
116    /// Creates an empty list of errors.
117    #[inline]
118    pub const fn new() -> CollectedErrors {
119        CollectedErrors { errors: None }
120    }
121
122    /// Returns `true` if no errors were collected.
123    #[inline]
124    pub fn is_empty(&self) -> bool {
125        self.errors.is_none()
126    }
127
128    fn add(&mut self, err: Error) {
129        match self.errors {
130            Some(ref mut errors) => errors.push_error(err),
131            None => self.errors = Some(err),
132        }
133    }
134
135    /// Collects the error of an item if errors are collected.
136    ///
137    /// If errors are not collected (or the limit of errors is reached, see
138    /// [`State::set_max_errors`]), the error is returned together with the
139    /// errors collected so far.  Errors which do not have the context of an
140    /// event attached yet (see [`Error`]) get the context of the current
141    /// event.
142    #[cold]
143    pub fn collect(&mut self, err: Error, state: &mut State) -> Result<(), Error> {
144        // errors that other containers collected already (and failed with
145        // once they were complete) do not count again
146        let new = err.uncollected_count();
147        if new == 0 && state.collects_errors() || state.take_error_slots(new) {
148            self.add(state.error_in_context(err).mark_collected());
149            Ok(())
150        } else if self.errors.is_none() {
151            Err(err)
152        } else {
153            // the new errors are not marked as collected: the containers the
154            // error passes through do not collect it either
155            self.add(state.error_in_context(err));
156            Err(self.take().unwrap())
157        }
158    }
159
160    /// Adds an error that is not the error of an item.
161    ///
162    /// This is for errors that are found once the container is complete,
163    /// for instance missing fields.  They are always added and do not count
164    /// towards the limit of errors.  Errors which do not have the context
165    /// of an event attached yet get the context of the current event.
166    #[cold]
167    pub fn push(&mut self, err: Error, state: &State) {
168        self.add(state.error_in_context(err).mark_collected());
169    }
170
171    /// Takes the collected errors as a single error.
172    ///
173    /// Returns `None` if there are none.
174    pub fn take(&mut self) -> Option<Error> {
175        self.errors.take()
176    }
177
178    /// Fails with the collected errors if there are any.
179    #[inline(always)]
180    pub fn finish(&mut self) -> Result<(), Error> {
181        if self.errors.is_none() {
182            Ok(())
183        } else {
184            Err(self.take_cold())
185        }
186    }
187
188    #[cold]
189    #[inline(never)]
190    fn take_cold(&mut self) -> Error {
191        self.errors.take().unwrap()
192    }
193}