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}