json_bourne/de.rs
1//! Type-driven deserialization.
2//!
3//! The [`FromJson`] trait is the heart of `json-bourne`. Each type knows how to
4//! parse itself from JSON given direct access to the [`Lexer`].
5//!
6//! Why a lexer instead of an event stream? Typed parsing already enforces
7//! the JSON grammar by virtue of which method gets called when — `Vec<T>`
8//! knows it's parsing an array, a struct knows it's parsing an object. The
9//! streaming `Event` API has to thread a state machine through every value
10//! to enforce the same grammar; for typed consumers that dispatch is pure
11//! overhead. By driving the lexer directly we skip the state machine.
12//!
13//! Inside `Vec<T>::from_lex` the loop is roughly:
14//!
15//! ```ignore
16//! lex.array_start()?; // consume `[`
17//! loop {
18//! out.push(T::from_lex(lex)?);
19//! if lex.array_continue(b']')? { break; }
20//! }
21//! ```
22//!
23//! Each element costs exactly one `T::from_lex` plus one `array_continue`
24//! — no per-element `next_event`, no `match self.state`.
25
26use crate::{Error, ErrorKind, Event, JsonNum, Lexer, Parser, ValueKind};
27
28/// Parse a value of type `T` from a slice of JSON bytes.
29pub fn parse<'input, T: FromJson<'input>>(input: &'input [u8]) -> Result<T, Error> {
30 let mut p: Parser<'input> = Parser::new(input);
31 let lex = p.lexer();
32 let value = T::from_lex(lex)?;
33 lex.finish()?;
34 Ok(value)
35}
36
37/// Parse from a `&str`.
38pub fn parse_str<'input, T: FromJson<'input>>(input: &'input str) -> Result<T, Error> {
39 parse(input.as_bytes())
40}
41
42/// Types that know how to deserialize themselves from JSON via a [`Lexer`].
43///
44/// The `'input` lifetime is the lifetime of the input bytes. Implementors
45/// that borrow from input (e.g. `&'input str`) tie their output to `'input`;
46/// owned implementors (e.g. `String`) leave `'input` unused.
47pub trait FromJson<'input>: Sized {
48 /// Parse one value of `Self` from the lexer's current position.
49 ///
50 /// Whitespace before the value is consumed by the lexer's value-reading
51 /// methods, so impls do not need to skip whitespace themselves.
52 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error>;
53
54 /// Optional fast path for `Vec<Self>`. The default implementation drives
55 /// `from_lex` once per element. Types where the per-element streaming
56 /// detour is pure overhead (the integer types, `&str`) override this to
57 /// lex-and-parse directly.
58 #[cfg(feature = "alloc")]
59 #[doc(hidden)]
60 fn vec_from_lex(lex: &mut Lexer<'input>) -> Result<alloc::vec::Vec<Self>, Error> {
61 let mut out = alloc::vec::Vec::new();
62 if lex.array_start()? {
63 return Ok(out);
64 }
65 out.push(Self::from_lex(lex)?);
66 while !lex.array_continue(b']')? {
67 out.push(Self::from_lex(lex)?);
68 }
69 Ok(out)
70 }
71}
72
73// ---------------------------------------------------------------------------
74// Primitive impls
75// ---------------------------------------------------------------------------
76
77#[inline]
78const fn type_error(lex: &Lexer<'_>, kind: ErrorKind) -> Error {
79 Error::new(kind, lex.position())
80}
81
82impl<'input> FromJson<'input> for bool {
83 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
84 match lex.read_value()? {
85 Event::Bool(b) => Ok(b),
86 _ => Err(type_error(lex, ErrorKind::ExpectedBool)),
87 }
88 }
89}
90
91impl<'input> FromJson<'input> for () {
92 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
93 match lex.read_value()? {
94 Event::Null => Ok(()),
95 _ => Err(type_error(lex, ErrorKind::ExpectedNull)),
96 }
97 }
98}
99
100impl<'input> FromJson<'input> for &'input str {
101 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
102 // The fast path: skip Event entirely.
103 match lex.peek_value_kind()? {
104 ValueKind::String => lex.parse_str_value(),
105 _ => Err(type_error(lex, ErrorKind::ExpectedString)),
106 }
107 }
108
109 /// Fused-pass fast path for `Vec<&str>`. Falls back to the streaming
110 /// path for the first element only so an immediate `]` (empty array)
111 /// is handled cleanly.
112 #[cfg(feature = "alloc")]
113 fn vec_from_lex(lex: &mut Lexer<'input>) -> Result<alloc::vec::Vec<Self>, Error> {
114 let mut out: alloc::vec::Vec<&'input str> = alloc::vec::Vec::new();
115 if lex.array_start()? {
116 return Ok(out);
117 }
118 out.push(lex.parse_str_value()?);
119 while !lex.array_continue(b']')? {
120 out.push(lex.parse_str_value()?);
121 }
122 Ok(out)
123 }
124}
125
126macro_rules! impl_int {
127 ($($t:ty => $accessor:ident),* $(,)?) => {
128 $(
129 impl<'input> FromJson<'input> for $t {
130 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
131 match lex.peek_value_kind()? {
132 ValueKind::Number => {
133 let n: JsonNum = lex.read_number()?;
134 let big = n.$accessor(lex.input())
135 .map_err(|kind| Error::new(kind, lex.position()))?;
136 <$t>::try_from(big).map_err(|_| {
137 Error::new(ErrorKind::NumberOutOfRange, lex.position())
138 })
139 }
140 _ => Err(type_error(lex, ErrorKind::ExpectedNumber)),
141 }
142 }
143
144 /// Fused-pass fast path: skip `JsonNum` entirely.
145 #[cfg(feature = "alloc")]
146 fn vec_from_lex(lex: &mut Lexer<'input>) -> Result<alloc::vec::Vec<Self>, Error> {
147 let mut out: alloc::vec::Vec<Self> = alloc::vec::Vec::new();
148 if lex.array_start()? {
149 return Ok(out);
150 }
151 let v = lex.parse_i64_value()?;
152 out.push(<$t>::try_from(v).map_err(|_| {
153 Error::new(ErrorKind::NumberOutOfRange, lex.position())
154 })?);
155 while !lex.array_continue(b']')? {
156 let v = lex.parse_i64_value()?;
157 out.push(<$t>::try_from(v).map_err(|_| {
158 Error::new(ErrorKind::NumberOutOfRange, lex.position())
159 })?);
160 }
161 Ok(out)
162 }
163 }
164 )*
165 };
166}
167
168impl_int!(i8 => as_i64, i16 => as_i64, i32 => as_i64, i64 => as_i64, isize => as_i64);
169impl_int!(u8 => as_u64, u16 => as_u64, u32 => as_u64, u64 => as_u64, usize => as_u64);
170
171// 128-bit ints — fused lex + decode via `parse_i128_value` /
172// `parse_u128_value`. The earlier path went through `JsonNum::as_*128`
173// which delegated to `str::parse::<i128>`; perf showed that taking 60%
174// of the `Vec<i128>` workload because `str::parse` uses checked
175// arithmetic on every digit. The bespoke parser skips overflow checks
176// for the first 38 digits (which always fit a `u128`).
177macro_rules! impl_int_wide {
178 ($($t:ty => $parse_fn:ident),* $(,)?) => {
179 $(
180 impl<'input> FromJson<'input> for $t {
181 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
182 match lex.peek_value_kind()? {
183 ValueKind::Number => lex.$parse_fn(),
184 _ => Err(type_error(lex, ErrorKind::ExpectedNumber)),
185 }
186 }
187
188 /// Fused-pass fast path for `Vec<Self>`: skip the
189 /// per-element peek-and-dispatch.
190 #[cfg(feature = "alloc")]
191 fn vec_from_lex(lex: &mut Lexer<'input>) -> Result<alloc::vec::Vec<Self>, Error> {
192 let mut out: alloc::vec::Vec<Self> = alloc::vec::Vec::new();
193 if lex.array_start()? {
194 return Ok(out);
195 }
196 out.push(lex.$parse_fn()?);
197 while !lex.array_continue(b']')? {
198 out.push(lex.$parse_fn()?);
199 }
200 Ok(out)
201 }
202 }
203 )*
204 };
205}
206
207impl_int_wide!(i128 => parse_i128_value, u128 => parse_u128_value);
208
209impl<'input> FromJson<'input> for f64 {
210 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
211 match lex.peek_value_kind()? {
212 ValueKind::Number => lex.parse_f64_value(),
213 _ => Err(type_error(lex, ErrorKind::ExpectedNumber)),
214 }
215 }
216
217 /// Fused-pass fast path for `Vec<f64>`: skip `JsonNum` and the
218 /// type-peek per element. The `array_continue` polarity is the
219 /// same shape the integer impls use.
220 #[cfg(feature = "alloc")]
221 fn vec_from_lex(lex: &mut Lexer<'input>) -> Result<alloc::vec::Vec<Self>, Error> {
222 let mut out: alloc::vec::Vec<Self> = alloc::vec::Vec::new();
223 if lex.array_start()? {
224 return Ok(out);
225 }
226 out.push(lex.parse_f64_value()?);
227 while !lex.array_continue(b']')? {
228 out.push(lex.parse_f64_value()?);
229 }
230 Ok(out)
231 }
232}
233
234impl<'input> FromJson<'input> for f32 {
235 /// Reject literals whose magnitude can't fit `f32` instead of
236 /// silently coercing to `±inf`. Subnormals and finite-but-imprecise
237 /// values still narrow as a normal cast (the JSON spec doesn't
238 /// promise lossless f32 round-trip; libstd's `f64 as f32` rounds
239 /// to the nearest representable value).
240 #[allow(clippy::cast_possible_truncation)]
241 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
242 let v = f64::from_lex(lex)?;
243 let narrowed = v as Self;
244 if narrowed.is_finite() {
245 Ok(narrowed)
246 } else {
247 Err(Error::new(ErrorKind::NumberOutOfRange, lex.position()))
248 }
249 }
250}
251
252// ---------------------------------------------------------------------------
253// Composite impls
254// ---------------------------------------------------------------------------
255
256impl<'input, T: FromJson<'input>> FromJson<'input> for Option<T> {
257 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
258 match lex.peek_value_kind()? {
259 ValueKind::Null => {
260 let _ = lex.read_value()?;
261 Ok(None)
262 }
263 _ => Ok(Some(T::from_lex(lex)?)),
264 }
265 }
266}
267
268impl<'input, T: FromJson<'input>, const N: usize> FromJson<'input> for [T; N] {
269 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
270 let mut slots: [Option<T>; N] = core::array::from_fn(|_| None);
271
272 let empty = lex.array_start()?;
273 if empty {
274 if N == 0 {
275 return Ok(core::array::from_fn(|i| {
276 slots[i].take().expect("slot filled")
277 }));
278 }
279 return Err(type_error(lex, ErrorKind::TypeMismatch));
280 }
281
282 for (i, slot) in slots.iter_mut().enumerate() {
283 *slot = Some(T::from_lex(lex)?);
284 let closed = lex.array_continue(b']')?;
285 if closed {
286 if i + 1 == N {
287 return Ok(core::array::from_fn(|i| {
288 slots[i].take().expect("slot filled")
289 }));
290 }
291 return Err(type_error(lex, ErrorKind::TypeMismatch));
292 }
293 }
294 // Filled all N slots without seeing `]` after the last one: too long.
295 Err(type_error(lex, ErrorKind::TypeMismatch))
296 }
297}
298
299// Tuples — keep small and explicit.
300//
301// The macro generates a fixed-arity walk: for `(A, B, C)` we parse A, then
302// require `,`; parse B, then require `,`; parse C, then require `]`.
303// `array_continue` returns true when it consumed `]` and false when it
304// consumed `,`, which is exactly the polarity we need for the last vs
305// non-last branch.
306macro_rules! impl_tuple {
307 ($last:tt: $LAST:ident $(, $idx:tt: $T:ident)*) => {
308 impl<'input, $LAST: FromJson<'input> $(, $T: FromJson<'input>)*>
309 FromJson<'input> for ($LAST, $($T,)*)
310 {
311 #[allow(non_snake_case)]
312 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
313 if lex.array_start()? {
314 return Err(type_error(lex, ErrorKind::TypeMismatch));
315 }
316 let $LAST = <$LAST>::from_lex(lex)?;
317 $(
318 if lex.array_continue(b']')? {
319 return Err(type_error(lex, ErrorKind::TypeMismatch));
320 }
321 let $T = <$T>::from_lex(lex)?;
322 )*
323 if !lex.array_continue(b']')? {
324 return Err(type_error(lex, ErrorKind::TypeMismatch));
325 }
326 let _ = ($last $(, $idx)*); // silence unused-tt warnings
327 Ok(($LAST, $($T,)*))
328 }
329 }
330 };
331}
332
333impl_tuple!(0: A);
334impl_tuple!(0: A, 1: B);
335impl_tuple!(0: A, 1: B, 2: C);
336impl_tuple!(0: A, 1: B, 2: C, 3: D);
337impl_tuple!(0: A, 1: B, 2: C, 3: D, 4: E);
338impl_tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F);
339
340// ---------------------------------------------------------------------------
341// alloc-gated impls
342// ---------------------------------------------------------------------------
343
344#[cfg(feature = "alloc")]
345pub use alloc_impls::{MapKey, key_to_cow};
346
347#[cfg(feature = "alloc")]
348mod alloc_impls {
349 extern crate alloc;
350 use super::{FromJson, type_error};
351 use crate::{Error, ErrorKind, JsonStr, Lexer, ValueKind};
352 use alloc::borrow::Cow;
353 use alloc::string::String;
354 use alloc::vec::Vec;
355
356 impl<'input> FromJson<'input> for String {
357 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
358 match lex.peek_value_kind()? {
359 ValueKind::String => {
360 // Drive the lexer directly with the no-validate variant.
361 // The decoder below performs the same validation walk
362 // as part of decoding, so paying validate_escapes here
363 // (the lexer's default) would be a redundant pass over
364 // every escaped string. perf showed this redundant
365 // pass at 42% of total time on Vec<String> with escapes.
366 let js = lex.read_string_no_validate()?;
367 decode_string(js, lex)
368 }
369 _ => Err(type_error(lex, ErrorKind::ExpectedString)),
370 }
371 }
372 }
373
374 /// Borrow-when-you-can, allocate-when-you-must. The right default for
375 /// most string fields: ~95% of production JSON has no escapes, so this
376 /// avoids the per-element allocation that `String` pays. When escapes
377 /// are present the cost is identical to `String`.
378 impl<'input> FromJson<'input> for Cow<'input, str> {
379 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
380 match lex.peek_value_kind()? {
381 ValueKind::String => {
382 let js = lex.read_string_no_validate()?;
383 if let Some(borrowed) = js.as_str(lex.input()) {
384 return Ok(Cow::Borrowed(borrowed));
385 }
386 Ok(Cow::Owned(decode_owned(js, lex)?))
387 }
388 _ => Err(type_error(lex, ErrorKind::ExpectedString)),
389 }
390 }
391 }
392
393 /// JSON has no `char` type — pick "string of exactly one Unicode
394 /// scalar value" as the convention. Empty strings, multi-character
395 /// strings, and strings whose decoded form is not exactly one
396 /// scalar all reject. Escapes are honored (e.g. `"\n"`, `"é"`).
397 impl<'input> FromJson<'input> for char {
398 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
399 match lex.peek_value_kind()? {
400 ValueKind::String => {
401 let js = lex.read_string_no_validate()?;
402 // Borrow path: no escapes — read the validated UTF-8
403 // directly and require exactly one scalar.
404 if let Some(borrowed) = js.as_str(lex.input()) {
405 return single_char(borrowed)
406 .ok_or_else(|| type_error(lex, ErrorKind::TypeMismatch));
407 }
408 // Escape path: decode into a small scratch buffer.
409 // Most escape sequences produce ≤4 UTF-8 bytes, so a
410 // small allocation is fine; we still error if the
411 // decoded content isn't exactly one scalar.
412 let decoded = decode_owned(js, lex)?;
413 single_char(&decoded).ok_or_else(|| type_error(lex, ErrorKind::TypeMismatch))
414 }
415 _ => Err(type_error(lex, ErrorKind::ExpectedString)),
416 }
417 }
418 }
419
420 // -----------------------------------------------------------------
421 // Map and set collections.
422 //
423 // JSON object keys are always strings; the lexer's `_lex`-suffixed
424 // key methods surface them as `JsonStr` so callers can decode
425 // escapes when present. `key_to_cow` below borrows when escape-free
426 // and decodes otherwise — yielding `Cow<'input, str>`. The MapKey
427 // adapter then converts that into the user's chosen K. Supported
428 // keys: String, Cow<'input, str>, and (escape-free only)
429 // &'input str.
430 //
431 // `BTreeMap`/`BTreeSet` are alloc-gated (live in `alloc`).
432 // `HashMap`/`HashSet` are std-gated (live in `std`).
433 // -----------------------------------------------------------------
434
435 /// Materialize an object key from a [`JsonStr`] span. Borrows when the
436 /// key is escape-free; decodes into an owned `String` otherwise.
437 pub fn key_to_cow<'input>(js: JsonStr, lex: &Lexer<'input>) -> Result<Cow<'input, str>, Error> {
438 if let Some(borrowed) = js.as_str(lex.input()) {
439 return Ok(Cow::Borrowed(borrowed));
440 }
441 Ok(Cow::Owned(decode_owned(js, lex)?))
442 }
443
444 /// Internal adapter from a decoded JSON key to the user's key type.
445 ///
446 /// Sealed by the limited set of impls we provide; users who need a
447 /// custom key type should hand-write the `FromJson` impl for the map
448 /// or wrap the key in a newtype.
449 ///
450 /// Returns `Result` because not every adapter is total — `&'input str`
451 /// keys can only borrow, so escaped keys reject with `InvalidEscape`.
452 pub trait MapKey<'input>: Sized {
453 fn from_key(key: Cow<'input, str>, lex: &Lexer<'input>) -> Result<Self, Error>;
454 }
455
456 impl<'input> MapKey<'input> for String {
457 #[inline]
458 fn from_key(key: Cow<'input, str>, _lex: &Lexer<'input>) -> Result<Self, Error> {
459 Ok(key.into_owned())
460 }
461 }
462
463 impl<'input> MapKey<'input> for Cow<'input, str> {
464 #[inline]
465 fn from_key(key: Self, _lex: &Lexer<'input>) -> Result<Self, Error> {
466 Ok(key)
467 }
468 }
469
470 impl<'input> MapKey<'input> for &'input str {
471 /// Borrowing `&'input str` keys cannot represent escape-bearing
472 /// keys, since the decoded form lives in a fresh allocation
473 /// outside the input. Reject those at runtime; callers that
474 /// expect escapes should use `Cow<'input, str>` or `String`.
475 #[inline]
476 fn from_key(key: Cow<'input, str>, lex: &Lexer<'input>) -> Result<Self, Error> {
477 match key {
478 Cow::Borrowed(s) => Ok(s),
479 Cow::Owned(_) => Err(type_error(lex, ErrorKind::InvalidEscape)),
480 }
481 }
482 }
483
484 trait DupMap<K, V> {
485 fn new_empty() -> Self;
486 fn try_insert(&mut self, k: K, v: V) -> bool;
487 }
488
489 impl<K: Ord, V> DupMap<K, V> for alloc::collections::BTreeMap<K, V> {
490 fn new_empty() -> Self {
491 Self::new()
492 }
493 fn try_insert(&mut self, k: K, v: V) -> bool {
494 self.insert(k, v).is_none()
495 }
496 }
497
498 #[cfg(feature = "std")]
499 impl<K, V, S> DupMap<K, V> for std::collections::HashMap<K, V, S>
500 where
501 K: ::core::hash::Hash + Eq,
502 S: ::core::hash::BuildHasher + Default,
503 {
504 fn new_empty() -> Self {
505 Self::with_hasher(S::default())
506 }
507 fn try_insert(&mut self, k: K, v: V) -> bool {
508 self.insert(k, v).is_none()
509 }
510 }
511
512 #[cfg(feature = "indexmap")]
513 impl<K, V, S> DupMap<K, V> for indexmap::IndexMap<K, V, S>
514 where
515 K: ::core::hash::Hash + Eq,
516 S: ::core::hash::BuildHasher + Default,
517 {
518 fn new_empty() -> Self {
519 Self::with_hasher(S::default())
520 }
521 fn try_insert(&mut self, k: K, v: V) -> bool {
522 self.insert(k, v).is_none()
523 }
524 }
525
526 fn parse_map<'input, K, V, M>(lex: &mut Lexer<'input>) -> Result<M, Error>
527 where
528 K: MapKey<'input>,
529 V: FromJson<'input>,
530 M: DupMap<K, V>,
531 {
532 if !matches!(lex.peek_value_kind()?, ValueKind::Object) {
533 return Err(type_error(lex, ErrorKind::TypeMismatch));
534 }
535 lex.object_start()?;
536 let mut out = M::new_empty();
537 let mut maybe_key = lex.object_first_key_lex()?;
538 while let Some(js) = maybe_key {
539 let key_cow = key_to_cow(js, lex)?;
540 let key = K::from_key(key_cow, lex)?;
541 let v = V::from_lex(lex)?;
542 if !out.try_insert(key, v) {
543 return Err(Error::new(ErrorKind::DuplicateKey, lex.position()));
544 }
545 maybe_key = lex.object_next_key_lex()?;
546 }
547 Ok(out)
548 }
549
550 impl<'input, K, V> FromJson<'input> for alloc::collections::BTreeMap<K, V>
551 where
552 K: MapKey<'input> + Ord,
553 V: FromJson<'input>,
554 {
555 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
556 parse_map(lex)
557 }
558 }
559
560 #[cfg(feature = "std")]
561 impl<'input, K, V, S> FromJson<'input> for std::collections::HashMap<K, V, S>
562 where
563 K: MapKey<'input> + ::core::hash::Hash + Eq,
564 V: FromJson<'input>,
565 S: ::core::hash::BuildHasher + Default,
566 {
567 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
568 parse_map(lex)
569 }
570 }
571
572 trait SetInsert<T> {
573 fn new_empty() -> Self;
574 fn push(&mut self, v: T);
575 }
576
577 impl<T: Ord> SetInsert<T> for alloc::collections::BTreeSet<T> {
578 fn new_empty() -> Self {
579 Self::new()
580 }
581 fn push(&mut self, v: T) {
582 self.insert(v);
583 }
584 }
585
586 #[cfg(feature = "std")]
587 impl<T, S> SetInsert<T> for std::collections::HashSet<T, S>
588 where
589 T: ::core::hash::Hash + Eq,
590 S: ::core::hash::BuildHasher + Default,
591 {
592 fn new_empty() -> Self {
593 Self::with_hasher(S::default())
594 }
595 fn push(&mut self, v: T) {
596 self.insert(v);
597 }
598 }
599
600 #[cfg(feature = "indexmap")]
601 impl<T, S> SetInsert<T> for indexmap::IndexSet<T, S>
602 where
603 T: ::core::hash::Hash + Eq,
604 S: ::core::hash::BuildHasher + Default,
605 {
606 fn new_empty() -> Self {
607 Self::with_hasher(S::default())
608 }
609 fn push(&mut self, v: T) {
610 self.insert(v);
611 }
612 }
613
614 fn parse_set<'input, T, C>(lex: &mut Lexer<'input>) -> Result<C, Error>
615 where
616 T: FromJson<'input>,
617 C: SetInsert<T>,
618 {
619 let mut out = C::new_empty();
620 if lex.array_start()? {
621 return Ok(out);
622 }
623 out.push(T::from_lex(lex)?);
624 while !lex.array_continue(b']')? {
625 out.push(T::from_lex(lex)?);
626 }
627 Ok(out)
628 }
629
630 impl<'input, T> FromJson<'input> for alloc::collections::BTreeSet<T>
631 where
632 T: FromJson<'input> + Ord,
633 {
634 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
635 parse_set(lex)
636 }
637 }
638
639 #[cfg(feature = "std")]
640 impl<'input, T, S> FromJson<'input> for std::collections::HashSet<T, S>
641 where
642 T: FromJson<'input> + ::core::hash::Hash + Eq,
643 S: ::core::hash::BuildHasher + Default,
644 {
645 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
646 parse_set(lex)
647 }
648 }
649
650 // -----------------------------------------------------------------
651 // std::time and std::net adapters.
652 //
653 // JSON has no native types for any of these, so we pick a single
654 // convention per type. These are deliberately simple — projects
655 // with bespoke encodings (RFC 3339 timestamps, custom Duration
656 // shapes) should hand-write a wrapper newtype.
657 // -----------------------------------------------------------------
658
659 /// Parse a `Duration` from JSON `Number` (seconds, possibly fractional).
660 /// Negative inputs and non-finite values are rejected. Subsecond
661 /// precision is preserved to nanosecond resolution.
662 ///
663 /// Implementation note: pre-validates the input to a finite,
664 /// non-negative value within `Duration`'s u64-seconds range, then
665 /// delegates to `Duration::from_secs_f64`. The earlier hand-rolled
666 /// `trunc`/`mul`/`round`/`clamp` sequence was ~3.5× slower than
667 /// `from_secs_f64` on profile (the libstd routine inlines a
668 /// branch-light decomposition of the f64 mantissa).
669 #[cfg(feature = "std")]
670 impl<'input> FromJson<'input> for std::time::Duration {
671 #[allow(clippy::cast_precision_loss)]
672 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
673 // Skip the `f64::from_lex` detour: that does a
674 // `peek_value_kind` first, which `parse_f64_value`'s
675 // own type check makes redundant for the Number arm.
676 let secs_f = match lex.peek_value_kind()? {
677 ValueKind::Number => lex.parse_f64_value()?,
678 _ => return Err(type_error(lex, ErrorKind::ExpectedNumber)),
679 };
680 // `Duration::from_secs_f64` panics on these inputs;
681 // convert to typed errors before calling.
682 if !secs_f.is_finite() || secs_f < 0.0 || secs_f >= (u64::MAX as f64) {
683 return Err(type_error(lex, ErrorKind::NumberOutOfRange));
684 }
685 Ok(Self::from_secs_f64(secs_f))
686 }
687
688 /// Fused-pass fast path for `Vec<Duration>`. Mirrors the
689 /// `Vec<f64>` override: `parse_f64_value` directly per
690 /// element, no type-peek detour past the first.
691 #[cfg(feature = "alloc")]
692 #[allow(clippy::cast_precision_loss)]
693 fn vec_from_lex(lex: &mut Lexer<'input>) -> Result<alloc::vec::Vec<Self>, Error> {
694 #[inline]
695 fn convert(lex: &Lexer<'_>, secs_f: f64) -> Result<std::time::Duration, Error> {
696 if !secs_f.is_finite() || secs_f < 0.0 || secs_f >= (u64::MAX as f64) {
697 return Err(type_error(lex, ErrorKind::NumberOutOfRange));
698 }
699 Ok(std::time::Duration::from_secs_f64(secs_f))
700 }
701 let mut out: alloc::vec::Vec<Self> = alloc::vec::Vec::new();
702 if lex.array_start()? {
703 return Ok(out);
704 }
705 let secs_f = lex.parse_f64_value()?;
706 out.push(convert(lex, secs_f)?);
707 while !lex.array_continue(b']')? {
708 let secs_f = lex.parse_f64_value()?;
709 out.push(convert(lex, secs_f)?);
710 }
711 Ok(out)
712 }
713 }
714
715 /// Parse a `SystemTime` from JSON `Number` (seconds since
716 /// `UNIX_EPOCH`, possibly fractional and possibly negative).
717 /// Mirrors the `Duration` adapter but allows negative values for
718 /// pre-epoch timestamps, which the `SystemTime` arithmetic model
719 /// supports.
720 ///
721 /// Subsecond precision is preserved to nanosecond resolution via
722 /// `Duration::from_secs_f64`.
723 #[cfg(feature = "std")]
724 impl<'input> FromJson<'input> for std::time::SystemTime {
725 #[allow(clippy::cast_precision_loss)]
726 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
727 let secs_f = match lex.peek_value_kind()? {
728 ValueKind::Number => lex.parse_f64_value()?,
729 _ => return Err(type_error(lex, ErrorKind::ExpectedNumber)),
730 };
731 // Reject non-finite inputs and clamp the magnitude to a
732 // range Duration::from_secs_f64 won't panic on.
733 if !secs_f.is_finite() || secs_f.abs() >= (u64::MAX as f64) {
734 return Err(type_error(lex, ErrorKind::NumberOutOfRange));
735 }
736 let abs = std::time::Duration::from_secs_f64(secs_f.abs());
737 let epoch = std::time::UNIX_EPOCH;
738 let st = if secs_f < 0.0 {
739 epoch.checked_sub(abs)
740 } else {
741 epoch.checked_add(abs)
742 };
743 st.ok_or_else(|| type_error(lex, ErrorKind::NumberOutOfRange))
744 }
745 }
746
747 /// Generic adapter for any type whose canonical text form is parseable
748 /// via `FromStr`. Used below for `IpAddr`, `Ipv4Addr`, `Ipv6Addr`,
749 /// `SocketAddr`, and `PathBuf`. Failures map to `TypeMismatch`.
750 #[cfg(feature = "std")]
751 fn parse_from_str<'input, T>(lex: &mut Lexer<'input>) -> Result<T, Error>
752 where
753 T: ::core::str::FromStr,
754 {
755 let cow: Cow<'input, str> = Cow::<'input, str>::from_lex(lex)?;
756 cow.parse::<T>()
757 .map_err(|_| type_error(lex, ErrorKind::TypeMismatch))
758 }
759
760 #[cfg(feature = "std")]
761 impl<'input> FromJson<'input> for std::net::IpAddr {
762 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
763 parse_from_str(lex)
764 }
765 }
766
767 #[cfg(feature = "std")]
768 impl<'input> FromJson<'input> for std::net::Ipv4Addr {
769 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
770 parse_from_str(lex)
771 }
772 }
773
774 #[cfg(feature = "std")]
775 impl<'input> FromJson<'input> for std::net::Ipv6Addr {
776 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
777 parse_from_str(lex)
778 }
779 }
780
781 #[cfg(feature = "std")]
782 impl<'input> FromJson<'input> for std::net::SocketAddr {
783 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
784 parse_from_str(lex)
785 }
786 }
787
788 /// `PathBuf::from` is infallible on every byte sequence that round-
789 /// trips through UTF-8, so this never fails after string decode.
790 /// Use `parse_from_str` anyway for symmetry with the other adapters.
791 #[cfg(feature = "std")]
792 impl<'input> FromJson<'input> for std::path::PathBuf {
793 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
794 let s: String = String::from_lex(lex)?;
795 Ok(Self::from(s))
796 }
797 }
798
799 /// Transparent wrapper: parses an inner `T` and boxes it. The JSON
800 /// shape is identical to `T`'s — there is no JSON construct that
801 /// "owns" a value the way a `Box` does, and serde's convention is
802 /// the same.
803 impl<'input, T: FromJson<'input>> FromJson<'input> for alloc::boxed::Box<T> {
804 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
805 T::from_lex(lex).map(Self::new)
806 }
807 }
808
809 /// Transparent wrapper, same as `Box<T>`. `Rc` is single-threaded;
810 /// users that need cross-thread sharing should use `Arc<T>` instead.
811 impl<'input, T: FromJson<'input>> FromJson<'input> for alloc::rc::Rc<T> {
812 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
813 T::from_lex(lex).map(Self::new)
814 }
815 }
816
817 /// Transparent wrapper. `Arc` requires `target_has_atomic = "ptr"`
818 /// transitively via `alloc::sync`; we don't gate it explicitly because
819 /// `json-bourne`'s supported targets all have it.
820 impl<'input, T: FromJson<'input>> FromJson<'input> for alloc::sync::Arc<T> {
821 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
822 T::from_lex(lex).map(Self::new)
823 }
824 }
825
826 /// Returns `Some(c)` iff `s` consists of exactly one Unicode scalar.
827 #[inline]
828 fn single_char(s: &str) -> Option<char> {
829 let mut it = s.chars();
830 let c = it.next()?;
831 if it.next().is_some() {
832 return None;
833 }
834 Some(c)
835 }
836
837 /// Owned-`String` decode given a `JsonStr`. Branches on `has_escapes`:
838 /// the no-escape path borrows the validated bytes and copies into a
839 /// fresh `String`; the escape path goes through `decode_owned`.
840 #[inline]
841 fn decode_string(js: JsonStr, lex: &Lexer<'_>) -> Result<String, Error> {
842 if let Some(borrowed) = js.as_str(lex.input()) {
843 return Ok(String::from(borrowed));
844 }
845 decode_owned(js, lex)
846 }
847
848 /// Shared owned-decode path for `String` and `Cow::Owned`. Pulled out
849 /// so the two impls cannot drift on capacity hint, error mapping, or
850 /// the (subtle) raw-bytes-missing case.
851 fn decode_owned(s: JsonStr, lex: &Lexer<'_>) -> Result<String, Error> {
852 // Capacity hint is the raw byte length: the decoded form is never
853 // longer than the encoded form (every escape sequence produces at
854 // most as many UTF-8 bytes as it occupies on the wire).
855 let raw = s
856 .raw_bytes(lex.input())
857 .ok_or_else(|| Error::new(ErrorKind::InvalidEscape, lex.position()))?;
858 let mut out = String::with_capacity(raw.len());
859 decode_escapes(raw, &mut out).map_err(|kind| Error::new(kind, lex.position()))?;
860 Ok(out)
861 }
862
863 impl<'input, T: FromJson<'input>> FromJson<'input> for Vec<T> {
864 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
865 T::vec_from_lex(lex)
866 }
867 }
868
869 /// SIMD-accelerated single-byte search for `\\` inside a slice.
870 /// Returns the offset of the first backslash, or `None` if none.
871 ///
872 /// Why this exists: the literal-byte run inside `decode_escapes` is
873 /// the inner loop on strings with sparse escapes (~1 escape per 50
874 /// bytes is typical for production payloads). On profile, the scalar
875 /// `while i < n && bytes[i] != b'\\'` walk was 64% of `decode_owned`'s
876 /// time. SSE2's `_mm_cmpeq_epi8` + `_mm_movemask_epi8` walks 16 bytes
877 /// per iteration with the same correctness; on `x86_64` the gain is
878 /// ~10x for long literal runs.
879 ///
880 /// Same `unsafe_code` justification as the parent function: SSE2
881 /// is part of the `x86_64` ABI baseline, the `target_feature` arm
882 /// is statically enabled on `x86_64`, and the unsafe is mechanical
883 /// (intrinsics carry unsafe by signature, not by memory-safety).
884 #[allow(unsafe_code)]
885 #[inline]
886 fn find_backslash(bytes: &[u8]) -> Option<usize> {
887 // Two distinct cfg-gated function bodies — splitting them into
888 // separate items per arch avoids a `return` inside one cfg
889 // branch (which clippy flags as `needless_return`) while
890 // keeping each arm a single expression. The `bourne_no_simd`
891 // cfg disables the SIMD path (used by miri).
892 #[cfg(all(target_arch = "x86_64", not(bourne_no_simd)))]
893 {
894 find_backslash_sse2(bytes)
895 }
896 #[cfg(not(all(target_arch = "x86_64", not(bourne_no_simd))))]
897 {
898 bytes.iter().position(|&b| b == b'\\')
899 }
900 }
901
902 #[cfg(all(target_arch = "x86_64", not(bourne_no_simd)))]
903 #[allow(unsafe_code, clippy::cast_possible_wrap, clippy::cast_sign_loss)]
904 #[inline]
905 fn find_backslash_sse2(bytes: &[u8]) -> Option<usize> {
906 use core::arch::x86_64::{
907 _mm_cmpeq_epi8, _mm_loadu_si128, _mm_movemask_epi8, _mm_set1_epi8,
908 };
909
910 let n = bytes.len();
911 let mut i = 0;
912 // SAFETY: SSE2 is part of the x86_64 ABI baseline; rustc's default
913 // target features include `+sse2`, so the intrinsics are statically
914 // available. `_mm_loadu_si128` is documented as accepting unaligned
915 // addresses, and the bounds check `i + 16 <= n` ensures the load
916 // stays inside `bytes`.
917 unsafe {
918 let backslash = _mm_set1_epi8(b'\\' as i8);
919 while i + 16 <= n {
920 let chunk = _mm_loadu_si128(bytes.as_ptr().add(i).cast());
921 let m = _mm_cmpeq_epi8(chunk, backslash);
922 let bits = _mm_movemask_epi8(m) as u32;
923 if bits != 0 {
924 return Some(i + bits.trailing_zeros() as usize);
925 }
926 i += 16;
927 }
928 }
929 // Tail: scalar walk for the final <16 bytes.
930 bytes[i..]
931 .iter()
932 .position(|&b| b == b'\\')
933 .map(|off| i + off)
934 }
935
936 /// Decode a JSON string body into `dst`, expanding escape sequences.
937 ///
938 /// `raw` is the bytes between (but not including) the surrounding `"`s,
939 /// produced by [`Lexer::read_string_no_validate`]. This function is
940 /// the *only* validator on that path: it covers every escape sequence
941 /// (each escape is inspected to dispatch into the right branch), every
942 /// hex digit (via `parse_hex4`), and every surrogate pairing — so the
943 /// lexer can skip the redundant `validate_escapes` walk.
944 ///
945 /// Output is always valid UTF-8: the non-escape bytes are validated by
946 /// the lexer's inline UTF-8 walk, and `\u`-derived bytes come from
947 /// `encode_utf8` on a checked `char`.
948 ///
949 /// # Safety justification for the `unsafe` block
950 ///
951 /// The literal-byte path uses `core::str::from_utf8_unchecked`. The
952 /// invariant: every byte in `raw` reached this function via the lexer,
953 /// which validates UTF-8 inline against the RFC 3629 byte ranges as it
954 /// scans (see `Parser::consume_utf8_multibyte` and `scan_ascii_string_run`
955 /// in the lexer). The bytes between escapes are therefore valid
956 /// UTF-8 by construction — re-validating them in safe code is the
957 /// `from_utf8` re-walk that perf showed at ~12% of total time (the
958 /// audit on 2026-05-19 measured the safe variant at 1.68× slower,
959 /// pushing json-bourne below `serde_json` on the escape-heavy workload).
960 /// `json-bourne`'s `unsafe_code = "deny"` lint is overridden for this one
961 /// function with `#[allow]`, mirroring the same localized exception
962 /// the lexer makes at the equivalent site.
963 ///
964 /// The outer loop dispatches between literal-byte runs and escape
965 /// sequences. Escape decoding is delegated to `decode_simple_escape`
966 /// (the 8 single-byte arms) and `decode_unicode_escape` (the `\u`
967 /// branch including surrogate-pair logic) so this fn stays inside
968 /// the project's cyclomatic-complexity budget.
969 #[allow(unsafe_code)]
970 fn decode_escapes(raw: &[u8], dst: &mut String) -> Result<(), ErrorKind> {
971 let mut i = 0;
972 while i < raw.len() {
973 if raw[i] != b'\\' {
974 // Literal byte run: find the next `\` (or end) and append the
975 // whole stretch in one push. This is the hot path for strings
976 // with sparse escapes (most production payloads).
977 //
978 // Use SIMD scan when available — the scalar walk that used
979 // to live here was 64% of total decode time on profile.
980 let start = i;
981 i = find_backslash(&raw[i..]).map_or(raw.len(), |off| i + off);
982 // SAFETY: see the function-level comment. The lexer
983 // validated these bytes as UTF-8 inline.
984 let chunk = unsafe { core::str::from_utf8_unchecked(&raw[start..i]) };
985 dst.push_str(chunk);
986 continue;
987 }
988 // At a backslash. Need at least one more byte.
989 i += 1;
990 if i >= raw.len() {
991 return Err(ErrorKind::InvalidEscape);
992 }
993 if raw[i] == b'u' {
994 i = decode_unicode_escape(raw, i, dst)?;
995 } else {
996 dst.push(decode_simple_escape(raw[i])?);
997 }
998 i += 1;
999 }
1000 Ok(())
1001 }
1002
1003 /// Decode a single non-`u` JSON escape byte to its char. The 8
1004 /// match arms (`"`, `\\`, `/`, `b`, `f`, `n`, `r`, `t`) plus the
1005 /// catch-all error arm live here so `decode_escapes` doesn't carry
1006 /// their cyclomatic complexity.
1007 #[inline]
1008 const fn decode_simple_escape(b: u8) -> Result<char, ErrorKind> {
1009 Ok(match b {
1010 b'"' => '"',
1011 b'\\' => '\\',
1012 b'/' => '/',
1013 b'b' => '\u{0008}',
1014 b'f' => '\u{000C}',
1015 b'n' => '\n',
1016 b'r' => '\r',
1017 b't' => '\t',
1018 _ => return Err(ErrorKind::InvalidEscape),
1019 })
1020 }
1021
1022 /// Decode `\uXXXX` (and optionally a surrogate-pair `\uYYYY`) into
1023 /// a char, push it to `dst`, and return the new index of the last
1024 /// byte consumed inside `raw`. `i` points at the `u` of the first
1025 /// escape. Returns the index of the last hex digit (the caller
1026 /// bumps by 1 to move past it).
1027 fn decode_unicode_escape(raw: &[u8], i: usize, dst: &mut String) -> Result<usize, ErrorKind> {
1028 if i + 5 > raw.len() {
1029 return Err(ErrorKind::InvalidUnicodeEscape);
1030 }
1031 let cp = parse_hex4(&raw[i + 1..i + 5])?;
1032 // After the four hex digits, the consumed-up-to index is i + 4.
1033 let new_i = i + 4;
1034 if (0xD800..=0xDBFF).contains(&cp) {
1035 return decode_surrogate_pair(raw, new_i, cp, dst);
1036 }
1037 if (0xDC00..=0xDFFF).contains(&cp) {
1038 return Err(ErrorKind::UnpairedSurrogate);
1039 }
1040 // BMP scalar — char::from_u32 always succeeds for values
1041 // outside the surrogate range.
1042 let ch = char::from_u32(cp).ok_or(ErrorKind::InvalidUnicodeEscape)?;
1043 dst.push(ch);
1044 Ok(new_i)
1045 }
1046
1047 /// Combine a high surrogate at position `i` with the low surrogate
1048 /// at `i+3..i+7`. Caller has validated the high half is in
1049 /// 0xD800..=0xDBFF. Returns the index of the last hex digit of the
1050 /// low half so the outer loop can resume.
1051 fn decode_surrogate_pair(
1052 raw: &[u8],
1053 i: usize,
1054 cp: u32,
1055 dst: &mut String,
1056 ) -> Result<usize, ErrorKind> {
1057 if i + 7 > raw.len() || raw[i + 1] != b'\\' || raw[i + 2] != b'u' {
1058 return Err(ErrorKind::UnpairedSurrogate);
1059 }
1060 let low = parse_hex4(&raw[i + 3..i + 7])?;
1061 if !(0xDC00..=0xDFFF).contains(&low) {
1062 return Err(ErrorKind::UnpairedSurrogate);
1063 }
1064 let high_off = cp - 0xD800;
1065 let low_off = low - 0xDC00;
1066 let scalar = 0x1_0000 + (high_off << 10) + low_off;
1067 let ch = char::from_u32(scalar).ok_or(ErrorKind::InvalidUnicodeEscape)?;
1068 dst.push(ch);
1069 Ok(i + 6) // skip `\uXXXX`
1070 }
1071
1072 /// Same digit-walk as the lexer's `parse_hex4`. Duplicated here
1073 /// rather than re-exporting because it is a four-line helper and
1074 /// keeping it private avoids widening the public API.
1075 fn parse_hex4(bytes: &[u8]) -> Result<u32, ErrorKind> {
1076 let mut v: u32 = 0;
1077 for &b in bytes {
1078 let d = match b {
1079 b'0'..=b'9' => b - b'0',
1080 b'a'..=b'f' => b - b'a' + 10,
1081 b'A'..=b'F' => b - b'A' + 10,
1082 _ => return Err(ErrorKind::InvalidUnicodeEscape),
1083 };
1084 v = (v << 4) | u32::from(d);
1085 }
1086 Ok(v)
1087 }
1088
1089 // Ensure JsonStr stays imported even if a future refactor drops the
1090 // direct reference. The trait impl above uses it transitively.
1091 #[allow(dead_code)]
1092 type _UseJsonStr = JsonStr;
1093
1094 // -----------------------------------------------------------------
1095 // IndexMap / IndexSet (optional `indexmap` feature).
1096 //
1097 // Mirror image of the BTreeMap / HashMap impls. The novel property
1098 // here is *insertion-order preservation*: the parsed map iterates
1099 // in the order keys appeared in the JSON input, which downstream
1100 // consumers depend on for stable output (canonical JSON, log
1101 // round-trips, golden-file tests).
1102 // -----------------------------------------------------------------
1103
1104 #[cfg(feature = "indexmap")]
1105 impl<'input, K, V, S> FromJson<'input> for indexmap::IndexMap<K, V, S>
1106 where
1107 K: MapKey<'input> + ::core::hash::Hash + Eq,
1108 V: FromJson<'input>,
1109 S: ::core::hash::BuildHasher + Default,
1110 {
1111 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
1112 parse_map(lex)
1113 }
1114 }
1115
1116 #[cfg(feature = "indexmap")]
1117 impl<'input, T, S> FromJson<'input> for indexmap::IndexSet<T, S>
1118 where
1119 T: FromJson<'input> + ::core::hash::Hash + Eq,
1120 S: ::core::hash::BuildHasher + Default,
1121 {
1122 fn from_lex(lex: &mut Lexer<'input>) -> Result<Self, Error> {
1123 parse_set(lex)
1124 }
1125 }
1126}