Skip to main content

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}