Skip to main content

deser_core/de/
lexical.rs

1//! Parsing of lexical atoms.
2//!
3//! See [`Atom::Lexical`](crate::Atom::Lexical) and [`LexicalRules`].
4use alloc::format;
5use alloc::string::String;
6use core::fmt::Write;
7use core::num::{IntErrorKind, ParseIntError};
8
9use crate::State;
10use crate::error::{Error, ErrorKind, discarded_error};
11
12/// The longest part of a value that is included in error messages.
13const MAX_QUOTED: usize = 64;
14
15/// How [lexical atoms](crate::Atom::Lexical) are interpreted.
16///
17/// Lexical atoms are text whose type the format cannot express.  The types
18/// they are delivered to interpret them: numbers and booleans parse them,
19/// strings take them as they are.  What text means beyond that depends on
20/// where it comes from.  Keys of JSON objects are strict (a `bool` key is
21/// `true` or `false`), everything in a query string or an environment
22/// variable is text so `on` and `yes` are booleans too and empty values are
23/// missing values.
24///
25/// The rules are an extension value in the [`State`] (see
26/// [`State::get_mut`]) which formats set, the default are the
27/// [strict](Self::STRICT) rules.  As they are part of the state (and not of
28/// the atoms), lexical atoms that are buffered and replayed are
29/// interpreted with the rules of the deserialization they are replayed in.
30///
31/// ```
32/// use deser::de::{DeserializeDriver, LexicalRules};
33/// use deser::{Atom, Text};
34///
35/// let mut out = None::<bool>;
36/// let mut driver = DeserializeDriver::new(&mut out);
37/// LexicalRules::LENIENT.set(driver.state_mut());
38/// driver.emit(Atom::Lexical(Text::borrowed("on"))).unwrap();
39/// drop(driver);
40/// assert_eq!(out, Some(true));
41/// ```
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct LexicalRules {
44    lenient_bools: bool,
45    empty_is_null: bool,
46}
47
48impl LexicalRules {
49    /// The rules for text that happens to be text, like the keys of JSON
50    /// objects.  This is the default.
51    ///
52    /// * booleans are `true` and `false`
53    /// * integers and floats are parsed with [`str::parse`]
54    /// * empty text is not a missing value
55    pub const STRICT: LexicalRules = LexicalRules {
56        lenient_bools: false,
57        empty_is_null: false,
58    };
59
60    /// The rules for formats where everything is text, like query strings
61    /// and environment variables.
62    ///
63    /// * booleans are `true`, `yes`, `on` and `1` and `false`, `no`, `off`
64    ///   and `0` (ignoring ASCII case)
65    /// * integers and floats are parsed with [`str::parse`]
66    /// * empty text is a missing value for types that do not accept it:
67    ///   `None` for an `Option<u32>`, `Some("")` for an `Option<String>`
68    ///   and `()`
69    ///
70    /// These formats typically also allow keys to repeat, a key given once
71    /// can then stand for a sequence of one value.  That is not a rule of
72    /// the text but of the maps they emit (see
73    /// [`ContainerShape::with_multimap`](crate::ContainerShape::with_multimap)).
74    pub const LENIENT: LexicalRules = LexicalRules {
75        lenient_bools: true,
76        empty_is_null: true,
77    };
78
79    /// Returns the rules of a deserialization.
80    #[inline]
81    pub fn of(state: &State) -> LexicalRules {
82        state.get::<LexicalRules>().copied().unwrap_or_default()
83    }
84
85    /// Sets the rules of a deserialization.
86    #[inline]
87    pub fn set(self, state: &mut State) {
88        *state.get_mut::<LexicalRules>() = self;
89    }
90
91    /// Sets if booleans are also `yes`, `on` and `1` and `no`, `off` and
92    /// `0` (ignoring ASCII case).
93    pub const fn with_lenient_bools(mut self, yes: bool) -> LexicalRules {
94        self.lenient_bools = yes;
95        self
96    }
97
98    /// Sets if empty text is a missing value for types that do not accept
99    /// it.
100    pub const fn with_empty_is_null(mut self, yes: bool) -> LexicalRules {
101        self.empty_is_null = yes;
102        self
103    }
104
105    /// Returns `true` if booleans are also `yes`, `on`, `1`, `no`, `off`
106    /// and `0`.
107    pub const fn lenient_bools(&self) -> bool {
108        self.lenient_bools
109    }
110
111    /// Returns `true` if empty text is a missing value for types that do
112    /// not accept it.
113    pub const fn empty_is_null(&self) -> bool {
114        self.empty_is_null
115    }
116}
117
118impl Default for LexicalRules {
119    fn default() -> LexicalRules {
120        LexicalRules::STRICT
121    }
122}
123
124/// The key under which maps hold their own content.
125///
126/// In some formats a value is text or a map that holds the text together
127/// with more entries: the elements of XML are their text (`<count>3</count>`)
128/// or, if they have attributes, a map (`<count unit="m">3</count>` is
129/// `{"@unit": "m", "$text": "3"}`).  Which of the two a value is depends on
130/// the input, not on the type it's deserialized into.  Formats like this
131/// set the key of the content in the [`State`] (see [`set`](Self::set)),
132/// and values are then passed on in the form the type accepts:
133///
134/// * A type that rejects a map (like `u32`) receives the value of the key
135///   of the content, the other entries are skipped.  If the map has no
136///   such key it receives empty text (`""` as
137///   [lexical atom](crate::Atom::Lexical)).
138/// * A type that rejects [lexical atoms](crate::Atom::Lexical) but accepts
139///   maps (like a struct) receives a map with the text under the key of the
140///   content (no entry for empty text).
141///
142/// Both only happen after a type rejected the value, so they cost nothing
143/// otherwise.  Without the key (the default), values are passed on as
144/// they are.
145///
146/// ```
147/// use deser::de::{ContentKey, DeserializeDriver};
148/// use deser::{Atom, Deserialize, Event};
149///
150/// #[derive(Deserialize, Debug, PartialEq)]
151/// struct Price {
152///     #[deser(rename = "@currency")]
153///     currency: Option<String>,
154///     #[deser(rename = "$text")]
155///     amount: u32,
156/// }
157///
158/// let mut out = None::<(u32, Price)>;
159/// let mut driver = DeserializeDriver::new(&mut out);
160/// ContentKey("$text").set(driver.state_mut());
161/// driver.emit(Event::seq_start()).unwrap();
162/// // a map for a `u32`
163/// driver.emit(Event::map_start()).unwrap();
164/// for text in ["@unit", "m", "$text", "3"] {
165///     driver.emit(Atom::Lexical(text.into())).unwrap();
166/// }
167/// driver.emit(Event::MapEnd).unwrap();
168/// // text for a struct
169/// driver.emit(Atom::Lexical("12".into())).unwrap();
170/// driver.emit(Event::SeqEnd).unwrap();
171/// drop(driver);
172/// assert_eq!(out, Some((3, Price { currency: None, amount: 12 })));
173/// ```
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
175pub struct ContentKey(pub &'static str);
176
177impl ContentKey {
178    /// Returns the key of the content of a deserialization if there is one.
179    #[inline]
180    pub fn of(state: &State) -> Option<&'static str> {
181        Some(state.content_key).filter(|key| !key.is_empty())
182    }
183
184    /// Sets the key of the content of a deserialization.
185    ///
186    /// The empty key means that there is no key of the content (the
187    /// default).
188    #[inline]
189    pub fn set(self, state: &mut State) {
190        state.content_key = self.0;
191    }
192}
193
194/// Parses the lexical form of a boolean with the rules of the state.
195pub(crate) fn parse_bool(value: &str, state: &State) -> Result<bool, Error> {
196    parse_bool_with(value, LexicalRules::of(state).lenient_bools, state)
197}
198
199/// Parses the lexical form of a boolean.
200///
201/// If `lenient` is set, the spellings of booleans in query strings,
202/// environment variables and command lines are accepted, ignoring ASCII
203/// case.
204pub(crate) fn parse_bool_with(value: &str, lenient: bool, state: &State) -> Result<bool, Error> {
205    if lenient {
206        const TRUE: [&str; 4] = ["true", "yes", "on", "1"];
207        const FALSE: [&str; 4] = ["false", "no", "off", "0"];
208        if TRUE.iter().any(|x| x.eq_ignore_ascii_case(value)) {
209            Ok(true)
210        } else if FALSE.iter().any(|x| x.eq_ignore_ascii_case(value)) {
211            Ok(false)
212        } else {
213            Err(invalid(
214                value,
215                "bool (true, yes, on, 1, false, no, off or 0)",
216                state,
217            ))
218        }
219    } else {
220        match value {
221            "true" => Ok(true),
222            "false" => Ok(false),
223            _ => Err(invalid(value, "bool (true or false)", state)),
224        }
225    }
226}
227
228/// Returns `true` if the text of a lexical atom is empty and empty text is
229/// a missing value.
230#[inline]
231pub(crate) fn is_empty_null(value: &str, state: &State) -> bool {
232    value.is_empty() && LexicalRules::of(state).empty_is_null
233}
234
235/// Converts the error of parsing an integer.
236#[cold]
237pub(crate) fn int_error(value: &str, err: ParseIntError, expecting: &str, state: &State) -> Error {
238    let kind = match err.kind() {
239        IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => ErrorKind::OutOfRange,
240        _ => ErrorKind::Unexpected,
241    };
242    if state.discards_errors {
243        return discarded_error(kind);
244    }
245    Error::new(kind, invalid_message(value, expecting))
246}
247
248/// Creates the error for a lexical atom that cannot be parsed.
249#[cold]
250pub(crate) fn invalid(value: &str, expecting: &str, state: &State) -> Error {
251    if state.discards_errors {
252        return discarded_error(ErrorKind::Unexpected);
253    }
254    Error::new(ErrorKind::Unexpected, invalid_message(value, expecting))
255}
256
257fn invalid_message(value: &str, expecting: &str) -> String {
258    let mut msg = String::from("invalid value ");
259    match value.char_indices().nth(MAX_QUOTED) {
260        Some((end, _)) => write!(msg, "{:?}...", &value[..end]).unwrap(),
261        None => write!(msg, "{:?}", value).unwrap(),
262    }
263    write!(msg, ", expected {}", expecting).unwrap();
264    msg
265}
266
267/// Creates the error for a number that does not fit into the type.
268#[cold]
269pub(crate) fn out_of_range(
270    value: &dyn core::fmt::Display,
271    expecting: &str,
272    state: &State,
273) -> Error {
274    if state.discards_errors {
275        return discarded_error(ErrorKind::OutOfRange);
276    }
277    Error::new(
278        ErrorKind::OutOfRange,
279        format!("invalid value {}, expected {}", value, expecting),
280    )
281}
282
283#[test]
284fn test_parse_bool() {
285    let state = State::new();
286    for value in ["true", "TRUE", "Yes", "on", "1"] {
287        assert!(parse_bool_with(value, true, &state).unwrap(), "{}", value);
288    }
289    for value in ["false", "False", "NO", "off", "0"] {
290        assert!(!parse_bool_with(value, true, &state).unwrap(), "{}", value);
291    }
292    for value in ["", "2", "y", "n", "t", "truee", " true"] {
293        assert!(parse_bool_with(value, true, &state).is_err(), "{}", value);
294    }
295    assert!(parse_bool(" true", &state).is_err());
296    assert!(parse_bool("true", &state).unwrap());
297    assert!(!parse_bool("false", &state).unwrap());
298    for value in ["TRUE", "yes", "on", "1", "0", "off"] {
299        assert!(parse_bool(value, &state).is_err(), "{}", value);
300    }
301}
302
303#[test]
304fn test_invalid_truncates() {
305    let err = invalid(&"x".repeat(100), "u32", &State::new());
306    assert_eq!(
307        err.message(),
308        format!("invalid value {:?}..., expected u32", "x".repeat(64))
309    );
310}