deser_core/de/unknown.rs
1// most of this is only used by derived structs
2#![cfg_attr(not(feature = "derive"), allow(dead_code))]
3use alloc::format;
4use alloc::sync::Arc;
5use alloc::vec::Vec;
6use core::fmt;
7
8use crate::Source;
9use crate::State;
10use crate::error::{Error, ErrorKind, push_expected};
11use crate::sync::{Mutex, MutexGuard};
12
13/// What happens with keys of structs that no field takes.
14///
15/// Derived structs ignore keys they do not know by default. This policy
16/// changes that for all structs of a deserialization, while
17/// `#[deser(deny_unknown_fields)]` rejects unknown keys for a single type
18/// regardless of the policy. It's an extension value, usually configured
19/// in the [`Context`](crate::Context) (or in the [`State`] of a single
20/// deserialization, see [`set`](Self::set)). To collect the unknown keys
21/// of a single deserialization see [`IgnoredFields`].
22///
23/// Only the struct that the key is given to decides: flattened fields are
24/// asked if they take a key first (see
25/// [`value_for_key`](crate::de::Sink::value_for_key)), so a key is only
26/// unknown if neither the struct nor any of its flattened fields take it.
27///
28/// ```
29/// use deser::de::UnknownFields;
30/// use deser::{Context, Deserialize};
31///
32/// #[derive(Deserialize, Debug)]
33/// struct Config {
34/// name: String,
35/// }
36///
37/// let config = deser_json::DeserializerConfig::builder()
38/// .context(Context::with(UnknownFields::Error))
39/// .build();
40/// let err = config
41/// .from_str::<Config>(r#"{"name": "demo", "nmae": "demo"}"#)
42/// .unwrap_err();
43/// assert_eq!(err.message(), "unknown field `nmae`, expected `name`");
44/// ```
45#[derive(Debug, Clone, Default)]
46#[non_exhaustive]
47pub enum UnknownFields {
48 /// Unknown keys are ignored.
49 #[default]
50 Ignore,
51 /// Unknown keys are rejected.
52 Error,
53 /// Unknown keys are ignored but reported to a [`IgnoredFields`].
54 ///
55 /// The collector is shared, so this is meant for a single
56 /// deserialization (see [`IgnoredFields`]).
57 Collect(IgnoredFields),
58}
59
60/// The policy of deserializations that do not set one.
61static IGNORE: UnknownFields = UnknownFields::Ignore;
62
63impl UnknownFields {
64 /// Returns the policy of a deserialization.
65 #[inline]
66 pub fn of(state: &State) -> &UnknownFields {
67 state.get::<UnknownFields>().unwrap_or(&IGNORE)
68 }
69
70 /// Sets the policy of a deserialization.
71 #[inline]
72 pub fn set(self, state: &mut State) {
73 *state.get_mut::<UnknownFields>() = self;
74 }
75}
76
77/// Collects the keys ignored with [`UnknownFields::Collect`].
78///
79/// Every ignored key is reported as an [`Error`] which carries the same
80/// information as if the key was rejected: the location (if the format
81/// provides it) and the context registered in the state (for instance the
82/// path with `deser-path`). The line and column are only available if the
83/// format provides the [`Source`] (see [`TrackLocations`](crate::TrackLocations)).
84///
85/// The collector is shared between its clones, the clone in the state
86/// reports to the one that was set up. This makes it an output of the
87/// deserialization rather than configuration: set the policy in the state
88/// of the deserialization (for instance in the setup callback of
89/// [`Deserializer::deserialize_with`](crate::de::Deserializer::deserialize_with))
90/// rather than in a [`Context`](crate::Context) that is shared. In a
91/// shared context the keys of all deserializations that use it (which
92/// might run on other threads) are reported to the same collector:
93///
94/// ```
95/// use deser::de::{Deserializer, IgnoredFields, UnknownFields};
96/// use deser::Deserialize;
97///
98/// #[derive(Deserialize)]
99/// struct Config {
100/// name: String,
101/// }
102///
103/// let ignored = IgnoredFields::new();
104/// let config: Config = deser_json::Deserializer::from_str(r#"{"name": "demo", "nmae": "x"}"#)
105/// .deserialize_with(|driver| {
106/// UnknownFields::Collect(ignored.clone()).set(driver.state_mut())
107/// })
108/// .unwrap();
109/// assert_eq!(config.name, "demo");
110/// let ignored = ignored.take();
111/// assert_eq!(ignored.len(), 1);
112/// assert_eq!(ignored[0].message(), "unknown field `nmae`, expected `name`");
113/// ```
114#[derive(Clone, Default)]
115pub struct IgnoredFields {
116 errors: Arc<Mutex<Vec<Error>>>,
117}
118
119impl IgnoredFields {
120 /// Creates an empty collector.
121 pub fn new() -> IgnoredFields {
122 IgnoredFields::default()
123 }
124
125 /// Takes the ignored keys reported so far.
126 pub fn take(&self) -> Vec<Error> {
127 core::mem::take(&mut *self.lock())
128 }
129
130 /// Returns the number of ignored keys reported so far.
131 pub fn len(&self) -> usize {
132 self.lock().len()
133 }
134
135 /// Returns `true` if no ignored keys were reported.
136 pub fn is_empty(&self) -> bool {
137 self.lock().is_empty()
138 }
139
140 fn lock(&self) -> MutexGuard<'_, Vec<Error>> {
141 self.errors.lock()
142 }
143
144 fn push(&self, err: Error) {
145 self.lock().push(err);
146 }
147}
148
149impl fmt::Debug for IgnoredFields {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 f.debug_tuple("IgnoredFields").field(&*self.lock()).finish()
152 }
153}
154
155/// Keys offered to a flattened value that it took before it knew that it
156/// does not use them.
157///
158/// Internally tagged enums take all keys until they know their variant. If
159/// they are flattened into a struct, the keys the variant does not take are
160/// unknown keys of that struct, which is only known once the struct already
161/// handed them out. They are reported through the state when the enum
162/// finishes. The struct the value is flattened into takes them after it
163/// finished its flattened fields. If that struct is flattened itself they
164/// are left for the struct it's flattened into.
165#[derive(Debug, Default)]
166pub(crate) struct UnclaimedKeys(Vec<Error>);
167
168/// Returns `true` if the names of unknown keys are needed.
169///
170/// Derived structs only retain the names of keys they do not know if this
171/// returns `true` (or they need them for other reasons).
172#[inline]
173pub(crate) fn wants_unknown_fields(state: &State) -> bool {
174 !matches!(UnknownFields::of(state), UnknownFields::Ignore)
175}
176
177/// Creates the error for an unknown key.
178///
179/// The expected field names are only listed if they are known, which is
180/// not the case if there are flattened fields.
181#[cold]
182pub(crate) fn unknown_field_error(key: &str, fields: Option<&[&str]>) -> Error {
183 let mut msg = format!("unknown field `{}`", key);
184 if let Some(fields) = fields {
185 push_expected(&mut msg, fields, "fields");
186 }
187 Error::new(ErrorKind::UnknownField, msg)
188}
189
190/// Handles a key of a struct that neither a field nor a flattened field took.
191///
192/// `offset` is the position of the key in the input, `fields` the names of
193/// the fields of the struct (empty names are flattened fields). If `deny`
194/// is set, the key is rejected regardless of the policy.
195#[cold]
196pub fn unknown_field(
197 key: &str,
198 offset: Option<usize>,
199 fields: &[&str],
200 deny: bool,
201 state: &mut State,
202) -> Result<(), Error> {
203 let fields = if fields.iter().any(|x| x.is_empty()) {
204 None
205 } else {
206 Some(fields)
207 };
208 let make_error = || {
209 let mut err = unknown_field_error(key, fields);
210 if let Some(offset) = offset {
211 err.set_offset(offset);
212 }
213 err
214 };
215 decide(make_error, deny, state)
216}
217
218/// Applies the policy for unknown keys to the error for a key.
219fn decide(make_error: impl FnOnce() -> Error, deny: bool, state: &mut State) -> Result<(), Error> {
220 if deny {
221 return Err(make_error());
222 }
223 match UnknownFields::of(state) {
224 UnknownFields::Ignore => Ok(()),
225 UnknownFields::Error => Err(make_error()),
226 UnknownFields::Collect(ignored) => {
227 let ignored = ignored.clone();
228 ignored.push(located(make_error(), state));
229 Ok(())
230 }
231 }
232}
233
234/// Attaches the context of the current event to an error that is not
235/// returned (and thus not located by the drivers and formats).
236fn located(mut err: Error, state: &State) -> Error {
237 state.attach_error_context(&mut err);
238 if let Some(source) = state.get::<Source>() {
239 err.resolve_position(source.0.as_bytes());
240 }
241 err
242}
243
244/// Reports a key a flattened value took but did not use (see
245/// [`UnclaimedKeys`]).
246///
247/// The error carries the context of the key, the state is the one of the
248/// ongoing deserialization.
249pub(crate) fn report_unclaimed_key(err: Error, state: &mut State) {
250 state.get_mut::<UnclaimedKeys>().0.push(err);
251}
252
253/// Handles the keys that flattened values took but did not use.
254///
255/// This is invoked by derived structs after finishing their flattened
256/// fields. Structs that are flattened themselves (`standalone` is `false`)
257/// leave the keys for the struct they are flattened into.
258pub fn unclaimed_keys(standalone: bool, deny: bool, state: &mut State) -> Result<(), Error> {
259 if !standalone {
260 return Ok(());
261 }
262 let keys = match state.get::<UnclaimedKeys>() {
263 Some(keys) if !keys.0.is_empty() => {
264 core::mem::take(&mut state.get_mut::<UnclaimedKeys>().0)
265 }
266 _ => return Ok(()),
267 };
268 for err in keys {
269 // the error already carries the context of the key
270 decide(|| err, deny, state)?;
271 }
272 Ok(())
273}