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}