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