Skip to main content

json_bourne/
lexer.rs

1//! Stateless JSON lexer.
2//!
3//! `Lexer` is the byte-walking layer. It knows how to recognize and consume
4//! one JSON token at a time — strings, numbers, keywords, structural bytes
5//! — but it does not enforce the grammar that says "an array element is
6//! followed by `,` or `]`." That bookkeeping lives in `Parser`, which wraps
7//! a `Lexer` plus a `State` enum.
8//!
9//! The split exists because typed consumers (`Vec<T>::from_lex`,
10//! `Struct::from_lex`) already enforce the grammar by virtue of which
11//! method they call when. They walk the input recursively and don't need
12//! the `State` dispatch — calling it per element is pure overhead. By
13//! exposing the lexer directly, those consumers skip the state machine
14//! entirely; only streaming consumers using `Parser::next_event` pay for
15//! it.
16//!
17//! Container nesting is still tracked here (for depth limiting and matched
18//! `]`/`}` validation), but it's a plain push/pop on `Stack`, not a state
19//! machine.
20
21use crate::error::{Error, ErrorKind, Position};
22use crate::event::{Event, JsonNum, JsonStr, MAX_INPUT_LEN};
23
24/// `i64::MIN`'s magnitude as a `u64`: `i64::MAX as u64 + 1`. This is the
25/// largest `u64` value whose negation still fits in `i64`. Used by
26/// `parse_i64_value` to validate sign-aware bounds — `-9223372036854775808`
27/// is legal even though `+9223372036854775808` is not.
28const I64_MIN_MAGNITUDE: u64 = (i64::MAX as u64) + 1;
29
30/// Sign-aware bounds check shared by `parse_i64_value` and its inner
31/// digit loop. Maps an unsigned magnitude `acc` and a sign bit to the
32/// final `i64`, or returns `Err(())` if the magnitude doesn't fit.
33#[inline]
34fn i64_from_unsigned_magnitude(acc: u64, negative: bool) -> Result<i64, ()> {
35    if negative {
36        // `i64::MIN`'s magnitude is exactly `I64_MIN_MAGNITUDE`; any
37        // larger magnitude doesn't fit. `0i64.wrapping_sub_unsigned(acc)`
38        // produces `i64::MIN` when `acc == I64_MIN_MAGNITUDE`.
39        if acc <= I64_MIN_MAGNITUDE {
40            return Ok(0i64.wrapping_sub_unsigned(acc));
41        }
42        return Err(());
43    }
44    i64::try_from(acc).map_err(|_| ())
45}
46
47/// `i128::MIN`'s magnitude as a `u128`. Same trick as `I64_MIN_MAGNITUDE`,
48/// scaled up. `parse_i128_value` accumulates into `u128` so the negative
49/// edge case (`-170141183460469231731687303715884105728`) is representable
50/// during the lex pass before the sign-aware bounds check.
51const I128_MIN_MAGNITUDE: u128 = (i128::MAX as u128) + 1;
52
53/// `u128::MAX` is `2^128 - 1` ≈ 3.4 × 10^38, so 38 decimal digits always
54/// fit a `u128` without overflow check. The 39-digit boundary is exactly
55/// `10^38`–`u128::MAX`; from digit 39 onward we have to use checked
56/// arithmetic. Mirrors the 19-digit fast path in `parse_i64_value`.
57const U128_FAST_DIGITS: u32 = 38;
58
59/// Default maximum container nesting depth.
60///
61/// Guards against pathological inputs (e.g. millions of `[`s) that would
62/// otherwise drive recursive consumers into stack overflow. Override at
63/// compile time by parameterizing [`Lexer`] (and [`Parser`](crate::Parser))
64/// with a different `MAX_DEPTH`.
65pub const DEFAULT_MAX_DEPTH: usize = 128;
66
67#[derive(Copy, Clone, Debug, PartialEq, Eq)]
68#[allow(clippy::redundant_pub_crate)]
69pub(crate) enum Frame {
70    Array,
71    Object,
72}
73
74/// Fixed-capacity nesting stack. Avoids `alloc` for the parser itself.
75///
76/// Capacity is fixed at compile time by `Lexer`'s `MAX_DEPTH` parameter,
77/// so the inline array sized to it is also the depth bound.
78#[derive(Debug)]
79#[allow(clippy::redundant_pub_crate)]
80pub(crate) struct Stack<const MAX_DEPTH: usize> {
81    frames: [Frame; MAX_DEPTH],
82    len: usize,
83}
84
85impl<const MAX_DEPTH: usize> Stack<MAX_DEPTH> {
86    pub(crate) const fn new() -> Self {
87        Self {
88            frames: [Frame::Array; MAX_DEPTH],
89            len: 0,
90        }
91    }
92
93    pub(crate) const fn push(&mut self, frame: Frame) -> Result<(), ()> {
94        if self.len >= MAX_DEPTH {
95            return Err(());
96        }
97        self.frames[self.len] = frame;
98        self.len += 1;
99        Ok(())
100    }
101
102    pub(crate) const fn pop(&mut self) -> Option<Frame> {
103        if self.len == 0 {
104            None
105        } else {
106            self.len -= 1;
107            Some(self.frames[self.len])
108        }
109    }
110
111    pub(crate) const fn top(&self) -> Option<Frame> {
112        if self.len == 0 {
113            None
114        } else {
115            Some(self.frames[self.len - 1])
116        }
117    }
118
119    pub(crate) const fn len(&self) -> usize {
120        self.len
121    }
122
123    pub(crate) const fn truncate(&mut self, new_len: usize) {
124        if new_len <= self.len {
125            self.len = new_len;
126        }
127    }
128}
129
130enum ObjectPeek {
131    Close,
132    Quote,
133    Comma,
134    Other,
135}
136
137/// Stateless JSON lexer over a borrowed byte slice.
138///
139/// Each `read_*` method consumes one syntactic token from the input. The
140/// caller is responsible for invoking the right method at the right time
141/// — there is no state machine that says "after reading a key, you must
142/// call `expect_byte(b':')` next." Typed consumers (`FromJson` impls) drive
143/// the lexer directly; streaming consumers go through `Parser` instead.
144#[derive(Debug)]
145pub struct Lexer<'input, const MAX_DEPTH: usize = DEFAULT_MAX_DEPTH> {
146    input: &'input [u8],
147    /// Byte offset of the next-to-read byte. Line and column are reconstructed
148    /// lazily from `input[..offset]` whenever a `Position` is needed (errors,
149    /// public `position()` calls). The hot path never touches them, which is
150    /// what lets `bump()` compile to a single increment.
151    offset: usize,
152    pub(crate) stack: Stack<MAX_DEPTH>,
153}
154
155/// Saved lexer position + nesting depth, restorable via [`Lexer::restore`].
156///
157/// Returned by [`Lexer::checkpoint`]. The two fields together capture
158/// everything a typed consumer might mutate while exploring an input
159/// speculatively — the byte cursor and the container-frame stack depth.
160/// Restoring rewinds both, putting the lexer back into the exact state it
161/// was in when the checkpoint was taken.
162///
163/// Used by enum dispatch for representations that must try a variant and
164/// retry another on failure (`#[bourne(untagged)]`) or that must locate a
165/// tag field before parsing the rest of the object
166/// (`#[bourne(tag = "...")]`).
167#[derive(Copy, Clone, Debug)]
168pub struct Checkpoint {
169    offset: usize,
170    stack_len: usize,
171}
172
173/// Result of `Lexer::peek_value_kind`. Tells a caller what kind of value
174/// will be produced by the next `read_*` call without committing to it.
175#[derive(Copy, Clone, Debug, PartialEq, Eq)]
176pub enum ValueKind {
177    Object,
178    Array,
179    String,
180    Number,
181    True,
182    False,
183    Null,
184}
185
186impl<'input, const MAX_DEPTH: usize> Lexer<'input, MAX_DEPTH> {
187    /// Construct a lexer over `input`.
188    ///
189    /// # Panics
190    ///
191    /// Panics if `input.len() > MAX_INPUT_LEN` (~2 GB). The packed offset
192    /// representation in `JsonStr`/`JsonNum` reserves the top bit of a `u32`
193    /// for `has_escapes`, so positions are limited to 31 bits. Real-world
194    /// JSON documents are far smaller than this; consumers needing larger
195    /// streams should chunk and parse incrementally.
196    #[must_use]
197    pub const fn new(input: &'input [u8]) -> Self {
198        assert!(input.len() <= MAX_INPUT_LEN, "input exceeds MAX_INPUT_LEN");
199        Self {
200            input,
201            offset: 0,
202            stack: Stack::new(),
203        }
204    }
205
206    #[must_use]
207    pub const fn position(&self) -> Position {
208        compute_position(self.input, self.offset)
209    }
210
211    /// The input slice the lexer was constructed with. Consumers use this
212    /// to materialize `&str`/`&[u8]` from `JsonStr` and `JsonNum`, which
213    /// store offsets rather than fat pointers.
214    #[must_use]
215    pub const fn input(&self) -> &'input [u8] {
216        self.input
217    }
218
219    #[must_use]
220    pub const fn offset(&self) -> usize {
221        self.offset
222    }
223
224    /// Snapshot the current cursor and nesting depth. Pair with
225    /// [`restore`](Self::restore) to roll the lexer back after a
226    /// speculative parse — typically used by `#[bourne(untagged)]` enum
227    /// dispatch to try variants in order.
228    ///
229    /// The returned [`Checkpoint`] is opaque: do not construct one yourself
230    /// or mix checkpoints across different `Lexer` instances.
231    #[must_use]
232    pub const fn checkpoint(&self) -> Checkpoint {
233        Checkpoint {
234            offset: self.offset,
235            stack_len: self.stack.len(),
236        }
237    }
238
239    /// Roll the lexer back to a previously taken [`Checkpoint`].
240    ///
241    /// Restores both the byte cursor and the container-frame stack depth.
242    /// Intended for the speculative-retry pattern: take a checkpoint,
243    /// attempt a parse, on `Err` call `restore` and try a different shape.
244    ///
245    /// The checkpoint must have been produced by `self.checkpoint()`. If
246    /// the checkpoint is from a different lexer or from after a `restore`
247    /// to a deeper depth, behavior is logically incoherent (the `truncate`
248    /// no-ops if asked to grow), though never memory-unsafe.
249    pub const fn restore(&mut self, cp: Checkpoint) {
250        self.offset = cp.offset;
251        self.stack.truncate(cp.stack_len);
252    }
253
254    /// Skip whitespace then peek at the next byte to determine the kind of
255    /// value that begins there. Does not consume the byte. Returns
256    /// `UnexpectedEof` if there is no next byte.
257    pub fn peek_value_kind(&mut self) -> Result<ValueKind, Error> {
258        self.skip_whitespace();
259        let b = self
260            .peek()
261            .ok_or_else(|| self.err(ErrorKind::UnexpectedEof))?;
262        match b {
263            b'{' => Ok(ValueKind::Object),
264            b'[' => Ok(ValueKind::Array),
265            b'"' => Ok(ValueKind::String),
266            b'-' | b'0'..=b'9' => Ok(ValueKind::Number),
267            b't' => Ok(ValueKind::True),
268            b'f' => Ok(ValueKind::False),
269            b'n' => Ok(ValueKind::Null),
270            other => Err(self.err(ErrorKind::UnexpectedByte(other))),
271        }
272    }
273
274    /// Skip whitespace then read one full JSON value, returning the matching
275    /// `Event`. For containers, opens the container (consuming `[` or `{`)
276    /// and pushes a frame onto the nesting stack — the caller is responsible
277    /// for matching `]`/`}` later via `read_array_continue` /
278    /// `read_object_continue` (or by going through `Parser`).
279    pub fn read_value(&mut self) -> Result<Event, Error> {
280        self.skip_whitespace();
281        let b = self
282            .peek()
283            .ok_or_else(|| self.err(ErrorKind::UnexpectedEof))?;
284        match b {
285            b'{' => {
286                self.bump();
287                self.push_frame(Frame::Object)?;
288                Ok(Event::StartObject)
289            }
290            b'[' => {
291                self.bump();
292                self.push_frame(Frame::Array)?;
293                Ok(Event::StartArray)
294            }
295            b'"' => self.read_string().map(Event::String),
296            b't' => self.read_keyword(b"true", Event::Bool(true)),
297            b'f' => self.read_keyword(b"false", Event::Bool(false)),
298            b'n' => self.read_keyword(b"null", Event::Null),
299            b'-' | b'0'..=b'9' => self.read_number().map(Event::Number),
300            other => Err(self.err(ErrorKind::UnexpectedByte(other))),
301        }
302    }
303
304    /// Pop a container frame; verifies the popped frame matches `expected`.
305    /// Caller has already consumed the closing `]` or `}`.
306    pub(crate) fn pop_frame(&mut self, expected: Frame) -> Result<(), Error> {
307        let popped = self
308            .stack
309            .pop()
310            .ok_or_else(|| self.err(ErrorKind::UnexpectedByte(b']')))?;
311        if popped != expected {
312            return Err(self.err(ErrorKind::TypeMismatch));
313        }
314        Ok(())
315    }
316
317    pub(crate) fn push_frame(&mut self, frame: Frame) -> Result<(), Error> {
318        self.stack
319            .push(frame)
320            .map_err(|()| self.err(ErrorKind::DepthLimitExceeded))
321    }
322
323    pub(crate) fn read_keyword(&mut self, kw: &[u8], event: Event) -> Result<Event, Error> {
324        for &expected in kw {
325            match self.peek() {
326                Some(b) if b == expected => self.bump(),
327                Some(b) => return Err(self.err(ErrorKind::UnexpectedByte(b))),
328                None => return Err(self.err(ErrorKind::UnexpectedEof)),
329            }
330        }
331        Ok(event)
332    }
333
334    /// Read a JSON string token. Cursor must be at the opening `"`. Returns
335    /// a `JsonStr` covering the bytes between the quotes (exclusive).
336    ///
337    /// When the body contains escape sequences, the deferred `validate_escapes`
338    /// pass runs before returning — every escape is checked for syntactic
339    /// validity (escape kind, hex digits, surrogate pairing). The contract
340    /// for stream/Event consumers: a returned `JsonStr` with
341    /// `has_escapes() == true` means the escapes are well-formed.
342    pub fn read_string(&mut self) -> Result<JsonStr, Error> {
343        self.read_string_inner(true)
344    }
345
346    /// Like [`read_string`](Self::read_string), but skip the deferred
347    /// `validate_escapes` pass. The caller commits to performing
348    /// equivalent validation as part of decoding (the typed `String`
349    /// / `Cow<str>` impls do exactly this).
350    ///
351    /// This exists because `validate_escapes` and an eager decoder do
352    /// overlapping work: the deferred validation walks the body checking
353    /// every escape; the decoder walks the body to actually emit the
354    /// decoded form, and naturally has to inspect every escape anyway.
355    /// On profile, the redundant `validate_escapes` walk was 42% of total
356    /// time on the `mixed_length_strings_with_escapes` corpus when going
357    /// to `Vec<String>`. Skipping it here gives the typed path a faster
358    /// route without weakening the stream-consumer contract.
359    pub fn read_string_no_validate(&mut self) -> Result<JsonStr, Error> {
360        self.read_string_inner(false)
361    }
362
363    fn read_string_inner(&mut self, validate: bool) -> Result<JsonStr, Error> {
364        debug_assert_eq!(self.peek(), Some(b'"'));
365        self.bump(); // opening quote
366        let start = self.offset;
367        let mut has_escapes = false;
368        loop {
369            let b = self
370                .peek()
371                .ok_or_else(|| self.err(ErrorKind::UnexpectedEof))?;
372            match b {
373                b'"' => {
374                    let end = self.offset;
375                    self.bump(); // closing quote
376                    if validate && has_escapes {
377                        let raw = &self.input[start..end];
378                        validate_escapes(raw).map_err(|kind| self.err(kind))?;
379                    }
380                    #[allow(clippy::cast_possible_truncation)]
381                    return Ok(JsonStr::new(start as u32, end as u32, has_escapes));
382                }
383                b'\\' => {
384                    has_escapes = true;
385                    self.bump();
386                    match self.peek() {
387                        Some(b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't') => {
388                            self.bump();
389                        }
390                        Some(b'u') => {
391                            self.bump();
392                            for _ in 0..4 {
393                                match self.peek() {
394                                    Some(b) if b.is_ascii_hexdigit() => self.bump(),
395                                    Some(b) => return Err(self.err(ErrorKind::UnexpectedByte(b))),
396                                    None => return Err(self.err(ErrorKind::UnexpectedEof)),
397                                }
398                            }
399                        }
400                        Some(_) => return Err(self.err(ErrorKind::InvalidEscape)),
401                        None => return Err(self.err(ErrorKind::UnexpectedEof)),
402                    }
403                }
404                0..=0x1F => return Err(self.err(ErrorKind::ControlCharInString)),
405                0x20..=0x7F => self.scan_ascii_string_run(),
406                _ => self.consume_utf8_multibyte()?,
407            }
408        }
409    }
410
411    /// Read a JSON number token. Cursor must be at `-` or a digit. Returns a
412    /// `JsonNum` covering the literal.
413    #[inline]
414    pub fn read_number(&mut self) -> Result<JsonNum, Error> {
415        let start = self.offset;
416
417        if self.peek() == Some(b'-') {
418            self.bump();
419        }
420
421        match self.peek() {
422            Some(b'0') => {
423                self.bump();
424            }
425            Some(b'1'..=b'9') => {
426                self.bump();
427                self.scan_digit_run();
428            }
429            Some(b) => return Err(self.err(ErrorKind::UnexpectedByte(b))),
430            None => return Err(self.err(ErrorKind::UnexpectedEof)),
431        }
432
433        if self.peek() == Some(b'.') {
434            self.bump();
435            let frac_start = self.offset;
436            self.scan_digit_run();
437            if self.offset == frac_start {
438                return Err(self.err(ErrorKind::InvalidNumber));
439            }
440        }
441
442        if matches!(self.peek(), Some(b'e' | b'E')) {
443            self.bump();
444            if matches!(self.peek(), Some(b'+' | b'-')) {
445                self.bump();
446            }
447            let exp_start = self.offset;
448            self.scan_digit_run();
449            if self.offset == exp_start {
450                return Err(self.err(ErrorKind::InvalidNumber));
451            }
452        }
453
454        #[allow(clippy::cast_possible_truncation)]
455        let result = JsonNum::new(start as u32, self.offset as u32);
456        Ok(result)
457    }
458
459    /// Parse a JSON integer directly into `i64`, fusing lex and conversion.
460    ///
461    /// Caller must position the lexer at the first byte of the value
462    /// (after any whitespace). Returns the parsed `i64` and leaves the
463    /// cursor at the byte after the number. Rejects fractional and
464    /// exponent forms — those are not integers.
465    pub fn parse_i64_value(&mut self) -> Result<i64, Error> {
466        let start = self.offset;
467        let bytes = self.input;
468        let mut i = start;
469
470        let negative = matches!(bytes.get(i), Some(&b'-'));
471        if negative {
472            i += 1;
473        }
474
475        match bytes.get(i).copied() {
476            Some(b'0') => {
477                i += 1;
478                self.offset = i;
479                if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
480                    return Err(self.err(ErrorKind::ExpectedNumber));
481                }
482                Ok(0)
483            }
484            Some(b'1'..=b'9') => self.parse_i64_digits(i, negative),
485            Some(b) => {
486                self.offset = i;
487                Err(self.err(ErrorKind::UnexpectedByte(b)))
488            }
489            None => {
490                self.offset = i;
491                Err(self.err(ErrorKind::UnexpectedEof))
492            }
493        }
494    }
495
496    /// Inner accumulation loop for `parse_i64_value` once a leading
497    /// `1..=9` digit has been confirmed at `start`. Walks digits as
498    /// `u64` (so positive `i64::MIN.unsigned_abs()` fits during the
499    /// lex pass) and then maps the magnitude to a signed result.
500    /// Splitting this out keeps `parse_i64_value` inside the project's
501    /// cyclomatic-complexity budget.
502    fn parse_i64_digits(&mut self, start: usize, negative: bool) -> Result<i64, Error> {
503        let bytes = self.input;
504        let end = bytes.len();
505        let mut i = start;
506        let mut acc: u64 = 0;
507        let mut count: u32 = 0;
508        while i < end {
509            let d = bytes[i].wrapping_sub(b'0');
510            if d >= 10 {
511                break;
512            }
513            if count < 19 {
514                // Up to 19 digits fit in u64 without overflow; the
515                // 20-digit boundary is u64::MAX.
516                acc = acc * 10 + u64::from(d);
517            } else {
518                acc = acc
519                    .checked_mul(10)
520                    .and_then(|v| v.checked_add(u64::from(d)))
521                    .ok_or_else(|| {
522                        self.offset = i;
523                        self.err(ErrorKind::NumberOutOfRange)
524                    })?;
525            }
526            i += 1;
527            count += 1;
528        }
529        self.offset = i;
530        if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
531            return Err(self.err(ErrorKind::ExpectedNumber));
532        }
533        i64_from_unsigned_magnitude(acc, negative)
534            .map_err(|()| self.err(ErrorKind::NumberOutOfRange))
535    }
536
537    /// Parse a JSON integer directly into `i128`, fusing lex and conversion.
538    ///
539    /// Same shape as [`parse_i64_value`] but scaled to 128-bit. On profile,
540    /// routing `Vec<i128>` through `JsonNum::as_i128` (which calls
541    /// `str::parse::<i128>`) was 60% of the workload; the generic
542    /// `str::parse` path uses checked arithmetic on every digit. The
543    /// fast path here skips overflow checks for the first 38 digits
544    /// (which always fit a `u128`) and only pays them on the 39-digit
545    /// boundary case.
546    ///
547    /// Caller must position the lexer at the first byte of the value.
548    /// Rejects fractional and exponent forms.
549    ///
550    /// [`parse_i64_value`]: Self::parse_i64_value
551    pub fn parse_i128_value(&mut self) -> Result<i128, Error> {
552        let start = self.offset;
553        let bytes = self.input;
554        let end = bytes.len();
555        let mut i = start;
556
557        let negative = matches!(bytes.get(i), Some(&b'-'));
558        if negative {
559            i += 1;
560        }
561
562        let digits_start = i;
563        match bytes.get(i).copied() {
564            Some(b'0') => i += 1,
565            Some(b'1'..=b'9') => {
566                // Accumulate as u128 so the negative edge case
567                // (i128::MIN's magnitude = i128::MAX + 1) fits during
568                // the lex pass; sign-aware bounds check at the end.
569                let mut acc: u128 = 0;
570                let mut count: u32 = 0;
571                while i < end {
572                    let d = bytes[i].wrapping_sub(b'0');
573                    if d >= 10 {
574                        break;
575                    }
576                    if count < U128_FAST_DIGITS {
577                        acc = acc * 10 + u128::from(d);
578                    } else {
579                        acc = acc
580                            .checked_mul(10)
581                            .and_then(|v| v.checked_add(u128::from(d)))
582                            .ok_or_else(|| {
583                                self.offset = i;
584                                self.err(ErrorKind::NumberOutOfRange)
585                            })?;
586                    }
587                    i += 1;
588                    count += 1;
589                }
590                if i == digits_start {
591                    self.offset = i;
592                    return Err(self.err(ErrorKind::InvalidNumber));
593                }
594                self.offset = i;
595                if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
596                    return Err(self.err(ErrorKind::ExpectedNumber));
597                }
598                if negative {
599                    if acc <= I128_MIN_MAGNITUDE {
600                        // Same wrapping_sub_unsigned trick as the i64
601                        // path — produces i128::MIN at the boundary,
602                        // correct negative i128 below it.
603                        return Ok(0i128.wrapping_sub_unsigned(acc));
604                    }
605                    return Err(self.err(ErrorKind::NumberOutOfRange));
606                }
607                if let Ok(n) = i128::try_from(acc) {
608                    return Ok(n);
609                }
610                return Err(self.err(ErrorKind::NumberOutOfRange));
611            }
612            Some(b) => {
613                self.offset = i;
614                return Err(self.err(ErrorKind::UnexpectedByte(b)));
615            }
616            None => {
617                self.offset = i;
618                return Err(self.err(ErrorKind::UnexpectedEof));
619            }
620        }
621        self.offset = i;
622        if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
623            return Err(self.err(ErrorKind::ExpectedNumber));
624        }
625        Ok(0)
626    }
627
628    /// Parse a JSON unsigned integer directly into `u128`, fusing lex
629    /// and conversion. Rejects negative literals, fractional, and
630    /// exponent forms.
631    ///
632    /// Caller must position the lexer at the first byte of the value.
633    pub fn parse_u128_value(&mut self) -> Result<u128, Error> {
634        let start = self.offset;
635        let bytes = self.input;
636        let end = bytes.len();
637        let mut i = start;
638
639        // Unsigned: a leading `-` is rejected outright.
640        if matches!(bytes.get(i), Some(&b'-')) {
641            self.offset = i;
642            return Err(self.err(ErrorKind::NumberOutOfRange));
643        }
644
645        let digits_start = i;
646        match bytes.get(i).copied() {
647            Some(b'0') => i += 1,
648            Some(b'1'..=b'9') => {
649                let mut acc: u128 = 0;
650                let mut count: u32 = 0;
651                while i < end {
652                    let d = bytes[i].wrapping_sub(b'0');
653                    if d >= 10 {
654                        break;
655                    }
656                    if count < U128_FAST_DIGITS {
657                        acc = acc * 10 + u128::from(d);
658                    } else {
659                        acc = acc
660                            .checked_mul(10)
661                            .and_then(|v| v.checked_add(u128::from(d)))
662                            .ok_or_else(|| {
663                                self.offset = i;
664                                self.err(ErrorKind::NumberOutOfRange)
665                            })?;
666                    }
667                    i += 1;
668                    count += 1;
669                }
670                if i == digits_start {
671                    self.offset = i;
672                    return Err(self.err(ErrorKind::InvalidNumber));
673                }
674                self.offset = i;
675                if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
676                    return Err(self.err(ErrorKind::ExpectedNumber));
677                }
678                return Ok(acc);
679            }
680            Some(b) => {
681                self.offset = i;
682                return Err(self.err(ErrorKind::UnexpectedByte(b)));
683            }
684            None => {
685                self.offset = i;
686                return Err(self.err(ErrorKind::UnexpectedEof));
687            }
688        }
689        self.offset = i;
690        if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
691            return Err(self.err(ErrorKind::ExpectedNumber));
692        }
693        Ok(0)
694    }
695
696    /// Parse a JSON number directly into `f64`, fusing lex and decode.
697    ///
698    /// Caller must position the lexer at the first byte of the value
699    /// (after any whitespace). Skips the `JsonNum` middle layer that
700    /// `read_number()` + `JsonNum::as_f64` would build — saves one
701    /// `Option`-wrapped slice and the per-element struct construction.
702    /// On profile, `Vec<f64>` was ~50% slower than `Vec<i64>` largely
703    /// because of this missing fast path.
704    ///
705    /// Rejects non-finite results (out-of-range literals like `1e400`
706    /// decode to `±inf` from `str::parse::<f64>`, which JSON disallows).
707    pub fn parse_f64_value(&mut self) -> Result<f64, Error> {
708        let start = self.offset;
709        // Reuse the byte-walk of `read_number` (it already handles the
710        // `-?` integer + optional `.frac` + optional `e[+-]?digits`
711        // grammar correctly). Then slice the run we just walked and
712        // hand it to libcore's `str::parse::<f64>` — the same routine
713        // `JsonNum::as_f64` calls, just without the JsonNum struct.
714        let _span = self.read_number()?;
715        let end = self.offset;
716        // SAFETY: `read_number` only advances over the JSON number
717        // grammar's ASCII subset (`-`, digits, `.`, `e`, `E`, `+`).
718        // Always valid UTF-8.
719        #[allow(unsafe_code)]
720        let s = unsafe { core::str::from_utf8_unchecked(&self.input[start..end]) };
721        let v: f64 = s.parse().map_err(|_| self.err(ErrorKind::InvalidNumber))?;
722        if v.is_finite() {
723            Ok(v)
724        } else {
725            Err(self.err(ErrorKind::NumberOutOfRange))
726        }
727    }
728
729    /// Read a JSON string and return it as a borrowed `&'input str`. Errors
730    /// if the string contains escape sequences — those require a caller-owned
731    /// decode buffer, which `json-bourne` does not allocate.
732    ///
733    /// Caller must position the lexer at the opening `"`. On return the
734    /// cursor is past the closing `"`. The returned slice points into the
735    /// original input — zero copy.
736    pub fn parse_str_value(&mut self) -> Result<&'input str, Error> {
737        match self.peek() {
738            Some(b'"') => self.bump(),
739            Some(b) => return Err(self.err(ErrorKind::UnexpectedByte(b))),
740            None => return Err(self.err(ErrorKind::UnexpectedEof)),
741        }
742        let start = self.offset;
743        loop {
744            let b = self
745                .peek()
746                .ok_or_else(|| self.err(ErrorKind::UnexpectedEof))?;
747            match b {
748                b'"' => {
749                    let end = self.offset;
750                    self.bump();
751                    let raw = &self.input[start..end];
752                    // SAFETY: every byte was validated against the RFC 3629
753                    // ranges by the byte walk above (ASCII fast arm or
754                    // `consume_utf8_multibyte`).
755                    return Ok(unsafe { core::str::from_utf8_unchecked(raw) });
756                }
757                b'\\' => return Err(self.err(ErrorKind::InvalidEscape)),
758                0..=0x1F => return Err(self.err(ErrorKind::ControlCharInString)),
759                0x20..=0x7F => self.scan_ascii_string_run(),
760                _ => self.consume_utf8_multibyte()?,
761            }
762        }
763    }
764
765    /// Skip whitespace then expect `,` or the array-end byte. Returns
766    /// `true` if at end (caller should stop), `false` to continue with
767    /// another element.
768    ///
769    /// On `]` this also pops the matching frame from the nesting stack so
770    /// a subsequent operation resumes correctly in the enclosing context.
771    #[inline]
772    pub fn array_continue(&mut self, end_byte: u8) -> Result<bool, Error> {
773        self.skip_whitespace();
774        match self.peek() {
775            Some(b) if b == end_byte => {
776                self.bump();
777                let frame = if end_byte == b']' {
778                    Frame::Array
779                } else {
780                    Frame::Object
781                };
782                self.pop_frame(frame)?;
783                Ok(true)
784            }
785            Some(b',') => {
786                self.bump();
787                self.skip_whitespace();
788                Ok(false)
789            }
790            Some(b) => Err(self.err(ErrorKind::UnexpectedByte(b))),
791            None => Err(self.err(ErrorKind::UnexpectedEof)),
792        }
793    }
794
795    fn peek_object(&self) -> ObjectPeek {
796        match self.peek() {
797            Some(b'}') => ObjectPeek::Close,
798            Some(b'"') => ObjectPeek::Quote,
799            Some(b',') => ObjectPeek::Comma,
800            Some(_) | None => ObjectPeek::Other,
801        }
802    }
803
804    fn close_object(&mut self) -> Result<(), Error> {
805        self.bump();
806        self.pop_frame(Frame::Object)
807    }
808
809    fn expect_byte(&mut self, expected: u8) -> Result<(), Error> {
810        match self.peek() {
811            Some(b) if b == expected => {
812                self.bump();
813                Ok(())
814            }
815            Some(b) => Err(self.err(ErrorKind::UnexpectedByte(b))),
816            None => Err(self.err(ErrorKind::UnexpectedEof)),
817        }
818    }
819
820    fn expect_colon(&mut self) -> Result<(), Error> {
821        self.skip_whitespace();
822        self.expect_byte(b':')?;
823        self.skip_whitespace();
824        Ok(())
825    }
826
827    fn advance_comma_to_quote(&mut self) -> Result<(), Error> {
828        self.bump();
829        self.skip_whitespace();
830        match self.peek_object() {
831            ObjectPeek::Quote => Ok(()),
832            _ => Err(self.unexpected_or_eof()),
833        }
834    }
835
836    /// After a `StartObject`, return the next key as a borrowed `&'input str`,
837    /// or `None` if the object closes immediately.
838    #[inline]
839    pub fn object_first_key(&mut self) -> Result<Option<&'input str>, Error> {
840        self.skip_whitespace();
841        match self.peek_object() {
842            ObjectPeek::Close => {
843                self.close_object()?;
844                Ok(None)
845            }
846            ObjectPeek::Quote => {
847                let key = self.parse_str_value()?;
848                self.expect_colon()?;
849                Ok(Some(key))
850            }
851            ObjectPeek::Comma | ObjectPeek::Other => Err(self.unexpected_or_eof()),
852        }
853    }
854
855    /// Like [`object_first_key`], but returns the key as a raw [`JsonStr`]
856    /// span.
857    ///
858    /// [`object_first_key`]: Self::object_first_key
859    #[inline]
860    pub fn object_first_key_lex(&mut self) -> Result<Option<JsonStr>, Error> {
861        self.skip_whitespace();
862        match self.peek_object() {
863            ObjectPeek::Close => {
864                self.close_object()?;
865                Ok(None)
866            }
867            ObjectPeek::Quote => {
868                let key = self.read_string_no_validate()?;
869                self.expect_colon()?;
870                Ok(Some(key))
871            }
872            ObjectPeek::Comma | ObjectPeek::Other => Err(self.unexpected_or_eof()),
873        }
874    }
875
876    /// After a field's value, advance to the next key or close the object.
877    #[inline]
878    pub fn object_next_key(&mut self) -> Result<Option<&'input str>, Error> {
879        self.skip_whitespace();
880        match self.peek_object() {
881            ObjectPeek::Close => {
882                self.close_object()?;
883                Ok(None)
884            }
885            ObjectPeek::Comma => {
886                self.advance_comma_to_quote()?;
887                let key = self.parse_str_value()?;
888                self.expect_colon()?;
889                Ok(Some(key))
890            }
891            ObjectPeek::Quote | ObjectPeek::Other => Err(self.unexpected_or_eof()),
892        }
893    }
894
895    /// Like [`object_next_key`], but returns the key as a raw [`JsonStr`]
896    /// span.
897    ///
898    /// [`object_next_key`]: Self::object_next_key
899    #[inline]
900    pub fn object_next_key_lex(&mut self) -> Result<Option<JsonStr>, Error> {
901        self.skip_whitespace();
902        match self.peek_object() {
903            ObjectPeek::Close => {
904                self.close_object()?;
905                Ok(None)
906            }
907            ObjectPeek::Comma => {
908                self.advance_comma_to_quote()?;
909                let key = self.read_string_no_validate()?;
910                self.expect_colon()?;
911                Ok(Some(key))
912            }
913            ObjectPeek::Quote | ObjectPeek::Other => Err(self.unexpected_or_eof()),
914        }
915    }
916
917    fn unexpected_or_eof(&self) -> Error {
918        self.peek().map_or_else(
919            || self.err(ErrorKind::UnexpectedEof),
920            |b| self.err(ErrorKind::UnexpectedByte(b)),
921        )
922    }
923
924    /// Expect the byte that opens an array (`[`), advance past it, push a
925    /// nesting frame, and skip whitespace to the first element (or `]`).
926    /// Returns `true` if the array is empty (the closing `]` has just been
927    /// consumed and the frame has been popped).
928    #[inline]
929    pub fn array_start(&mut self) -> Result<bool, Error> {
930        self.skip_whitespace();
931        match self.peek() {
932            Some(b'[') => {
933                self.bump();
934                self.push_frame(Frame::Array)?;
935                self.skip_whitespace();
936                if self.peek() == Some(b']') {
937                    self.bump();
938                    self.pop_frame(Frame::Array)?;
939                    Ok(true)
940                } else {
941                    Ok(false)
942                }
943            }
944            Some(b) => Err(self.err(ErrorKind::UnexpectedByte(b))),
945            None => Err(self.err(ErrorKind::UnexpectedEof)),
946        }
947    }
948
949    /// Expect the byte that opens an object (`{`), advance past it, push a
950    /// nesting frame, and skip whitespace. Does not consume any keys.
951    #[inline]
952    pub fn object_start(&mut self) -> Result<(), Error> {
953        self.skip_whitespace();
954        match self.peek() {
955            Some(b'{') => {
956                self.bump();
957                self.push_frame(Frame::Object)?;
958                self.skip_whitespace();
959                Ok(())
960            }
961            Some(b) => Err(self.err(ErrorKind::UnexpectedByte(b))),
962            None => Err(self.err(ErrorKind::UnexpectedEof)),
963        }
964    }
965
966    /// Require that no further (non-whitespace) data follows. Used by
967    /// the typed entry point to reject `"1 2"` and similar.
968    pub fn finish(&mut self) -> Result<(), Error> {
969        self.skip_whitespace();
970        if self.peek().is_some() {
971            Err(self.err(ErrorKind::TrailingData))
972        } else {
973            Ok(())
974        }
975    }
976
977    /// Consume one complete JSON value and discard it.
978    ///
979    /// Walks whatever value sits at the cursor — primitive, string,
980    /// number, array, or object — and advances past it. For composite
981    /// values, every nested element is also skipped. The structural
982    /// frame stack stays balanced: this method pushes and pops the
983    /// same frames `read_value` would.
984    ///
985    /// Validation is the same as `read_value`: malformed input
986    /// (control char in string, lone surrogate, malformed number,
987    /// etc.) still raises an `Error`. The "skip" here means "throw
988    /// away the value", not "throw away the parse". A lenient
989    /// `deny_unknown_fields = false` consumer wants the cursor
990    /// advanced, but it still wants the surrounding object to
991    /// parse correctly afterward — which requires lexing the skipped
992    /// value to find its end.
993    ///
994    /// Used by `#[derive(FromJson)]` when a struct opts into
995    /// `#[bourne(deny_unknown_fields = false)]` to consume the value
996    /// associated with an unrecognized key.
997    pub fn skip_value(&mut self) -> Result<(), Error> {
998        let event = self.read_value()?;
999        match event {
1000            Event::StartArray => self.skip_array_body(),
1001            Event::StartObject => self.skip_object_body(),
1002            // Primitives consumed inline by `read_value`; nothing to
1003            // do but return.
1004            Event::String(_) | Event::Number(_) | Event::Bool(_) | Event::Null => Ok(()),
1005            // `read_value` only returns Start*/scalar events. The
1006            // End*/Key variants are produced by the streaming
1007            // Parser, not the bare lexer, so they cannot appear
1008            // here. Match exhaustively anyway so a future Event
1009            // variant is a compile error rather than a silent skip.
1010            Event::EndArray | Event::EndObject | Event::Key(_) => {
1011                Err(self.err(ErrorKind::UnexpectedByte(b']')))
1012            }
1013        }
1014    }
1015
1016    /// Drive `array_continue` until the matching `]` closes the frame.
1017    /// `read_value` already consumed the opening `[` and pushed the
1018    /// frame; this finishes the job. Used only from `skip_value`.
1019    fn skip_array_body(&mut self) -> Result<(), Error> {
1020        // Empty array: `]` follows immediately, with the frame already
1021        // pushed by read_value. We need to consume `]` and pop. The
1022        // shared logic lives in array_continue, so peek and dispatch.
1023        self.skip_whitespace();
1024        if matches!(self.peek(), Some(b']')) {
1025            self.bump();
1026            return self.pop_frame(Frame::Array);
1027        }
1028        // Non-empty: at least one element, then either `,` (continue)
1029        // or `]` (done).
1030        self.skip_value()?;
1031        while !self.array_continue(b']')? {
1032            self.skip_value()?;
1033        }
1034        Ok(())
1035    }
1036
1037    /// Drive `object_first_key` / `object_next_key` until the matching
1038    /// `}` closes the frame. The keys themselves are consumed (we
1039    /// don't need them); only the values need explicit skipping.
1040    fn skip_object_body(&mut self) -> Result<(), Error> {
1041        let mut key = self.object_first_key()?;
1042        while key.is_some() {
1043            self.skip_value()?;
1044            key = self.object_next_key()?;
1045        }
1046        Ok(())
1047    }
1048
1049    // -------------------------------------------------------------------
1050    // byte-level helpers
1051    // -------------------------------------------------------------------
1052
1053    #[inline]
1054    fn scan_ascii_string_run(&mut self) {
1055        // x86_64 ABI guarantees SSE2 — no runtime detection needed.
1056        // The `bourne_no_simd` cfg disables the SIMD path; used by miri
1057        // (which doesn't model SSE2 intrinsics) and by curious users.
1058        #[cfg(all(target_arch = "x86_64", not(bourne_no_simd)))]
1059        // SAFETY: SSE2 is part of the x86_64 ABI baseline. Every x86_64
1060        // CPU has it; rustc's default target features include `+sse2`.
1061        // The intrinsics are `unsafe` by signature, not because we're
1062        // doing anything memory-unsafe — `_mm_loadu_si128` accepts
1063        // unaligned pointers and we walk only valid input bytes.
1064        unsafe {
1065            self.scan_ascii_string_run_sse2();
1066        }
1067        #[cfg(not(all(target_arch = "x86_64", not(bourne_no_simd))))]
1068        self.scan_ascii_string_run_scalar();
1069    }
1070
1071    /// Scalar fallback for the ASCII string scan. Used on non-x86_64 targets
1072    /// and as the inner loop's tail when fewer than 16 bytes remain.
1073    #[inline]
1074    fn scan_ascii_string_run_scalar(&mut self) {
1075        let bytes = self.input;
1076        let mut i = self.offset;
1077        let end = bytes.len();
1078        while i < end {
1079            let b = bytes[i];
1080            if b == b'"' || b == b'\\' || !(0x20..0x80).contains(&b) {
1081                break;
1082            }
1083            i += 1;
1084        }
1085        self.offset = i;
1086    }
1087
1088    /// SSE2-accelerated ASCII string scan. Walks 16 bytes at a time looking
1089    /// for the first "stop byte" (`"`, `\`, control char <0x20, or high-bit
1090    /// byte ≥0x80) and advances `self.offset` to it.
1091    ///
1092    /// Algorithm: load 16 bytes, build a 16-bit bitmask where bit `k` is set
1093    /// iff `bytes[i+k]` is a stop byte. If any bit is set, advance by the
1094    /// trailing-zero count to land on the first stop byte. Otherwise advance
1095    /// by 16 and continue.
1096    ///
1097    /// The "control or high-bit" test is fused into a single `cmplt_epi8`:
1098    /// reading bytes as `i8`, both `<0x20` (e.g. `0x05` = 5) and `≥0x80`
1099    /// (e.g. `0xC3` = -61) compare-less-than the constant 0x20. So one
1100    /// signed-compare instruction covers both stop categories.
1101    ///
1102    /// # Safety
1103    ///
1104    /// Only the SSE2 target feature is required. On `x86_64` it's part of the
1105    /// ABI baseline; the cfg gate at the call site enforces this.
1106    #[cfg(all(target_arch = "x86_64", not(bourne_no_simd)))]
1107    #[target_feature(enable = "sse2")]
1108    #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
1109    unsafe fn scan_ascii_string_run_sse2(&mut self) {
1110        use core::arch::x86_64::{
1111            _mm_cmpeq_epi8, _mm_cmplt_epi8, _mm_loadu_si128, _mm_movemask_epi8, _mm_or_si128,
1112            _mm_set1_epi8,
1113        };
1114
1115        let bytes = self.input;
1116        let end = bytes.len();
1117        let mut i = self.offset;
1118
1119        // Splat constants. The `as i8` casts wrap by design — SSE2 byte
1120        // compares are always signed at the silicon level; we want the bit
1121        // patterns for `"`, `\`, and 0x20 regardless of sign interpretation.
1122        let quote = _mm_set1_epi8(b'"' as i8);
1123        let backslash = _mm_set1_epi8(b'\\' as i8);
1124        // `cmplt_epi8(b, 0x20)` flags both `b<0x20` (controls) AND `b>=0x80`
1125        // (high-bit bytes interpreted as negative i8). One compare, two stops.
1126        let lt_threshold = _mm_set1_epi8(0x20_i8);
1127
1128        while i + 16 <= end {
1129            // SAFETY: `i + 16 <= end` checked above; the pointer + 16 bytes
1130            // lie inside `bytes`. `_mm_loadu_si128` accepts unaligned addresses.
1131            let chunk = unsafe { _mm_loadu_si128(bytes.as_ptr().add(i).cast()) };
1132            let m_quote = _mm_cmpeq_epi8(chunk, quote);
1133            let m_back = _mm_cmpeq_epi8(chunk, backslash);
1134            let m_ctrl_or_hi = _mm_cmplt_epi8(chunk, lt_threshold);
1135            let mask = _mm_or_si128(_mm_or_si128(m_quote, m_back), m_ctrl_or_hi);
1136            // movemask returns i32 in [0, 0xFFFF]; cast to u32 is lossless.
1137            let bits = _mm_movemask_epi8(mask) as u32;
1138            if bits != 0 {
1139                i += bits.trailing_zeros() as usize;
1140                self.offset = i;
1141                return;
1142            }
1143            i += 16;
1144        }
1145
1146        // Tail: scalar walk for the final <16 bytes.
1147        self.offset = i;
1148        self.scan_ascii_string_run_scalar();
1149    }
1150
1151    #[inline]
1152    fn consume_utf8_multibyte(&mut self) -> Result<(), Error> {
1153        let leading = self
1154            .peek()
1155            .ok_or_else(|| self.err(ErrorKind::InvalidUtf8))?;
1156
1157        let (extra, second_lo, second_hi) =
1158            utf8_leading_byte_info(leading).ok_or_else(|| self.err(ErrorKind::InvalidUtf8))?;
1159        self.bump();
1160
1161        match self.peek() {
1162            Some(b) if b >= second_lo && b <= second_hi => self.bump(),
1163            _ => return Err(self.err(ErrorKind::InvalidUtf8)),
1164        }
1165        for _ in 1..extra {
1166            match self.peek() {
1167                Some(0x80..=0xBF) => self.bump(),
1168                _ => return Err(self.err(ErrorKind::InvalidUtf8)),
1169            }
1170        }
1171        Ok(())
1172    }
1173
1174    fn scan_digit_run(&mut self) {
1175        let bytes = self.input;
1176        let mut i = self.offset;
1177        let end = bytes.len();
1178        while i < end {
1179            let b = bytes[i];
1180            if b.wrapping_sub(b'0') >= 10 {
1181                break;
1182            }
1183            i += 1;
1184        }
1185        self.offset = i;
1186    }
1187
1188    pub(crate) fn skip_whitespace(&mut self) {
1189        let bytes = self.input;
1190        let mut i = self.offset;
1191        let end = bytes.len();
1192        while i < end {
1193            let b = bytes[i];
1194            if b == b' ' || b == b'\t' || b == b'\n' || b == b'\r' {
1195                i += 1;
1196            } else {
1197                break;
1198            }
1199        }
1200        self.offset = i;
1201    }
1202
1203    pub(crate) fn peek(&self) -> Option<u8> {
1204        self.input.get(self.offset).copied()
1205    }
1206
1207    pub(crate) fn bump(&mut self) {
1208        debug_assert!(self.offset < self.input.len());
1209        self.offset += 1;
1210    }
1211
1212    pub(crate) const fn err(&self, kind: ErrorKind) -> Error {
1213        Error::new(kind, compute_position(self.input, self.offset))
1214    }
1215}
1216
1217#[allow(clippy::cast_possible_truncation)]
1218const fn compute_position(_input: &[u8], offset: usize) -> Position {
1219    Position::new(offset as u32)
1220}
1221
1222/// Decode a UTF-8 leading byte into `(extra, lo, hi)` for the second byte.
1223/// Returns `None` for bytes that aren't valid UTF-8 sequence starters.
1224#[inline]
1225const fn utf8_leading_byte_info(b: u8) -> Option<(u8, u8, u8)> {
1226    match b {
1227        0xC2..=0xDF => Some((1, 0x80, 0xBF)),
1228        0xE0 => Some((2, 0xA0, 0xBF)),
1229        0xE1..=0xEC | 0xEE..=0xEF => Some((2, 0x80, 0xBF)),
1230        0xED => Some((2, 0x80, 0x9F)),
1231        0xF0 => Some((3, 0x90, 0xBF)),
1232        0xF1..=0xF3 => Some((3, 0x80, 0xBF)),
1233        0xF4 => Some((3, 0x80, 0x8F)),
1234        _ => None,
1235    }
1236}
1237
1238fn validate_escapes(raw: &[u8]) -> Result<(), ErrorKind> {
1239    let mut i = 0;
1240    while i < raw.len() {
1241        let b = raw[i];
1242        if b == b'\\' {
1243            i += 1;
1244            if i >= raw.len() {
1245                return Err(ErrorKind::InvalidEscape);
1246            }
1247            match raw[i] {
1248                b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't' => i += 1,
1249                b'u' => {
1250                    if i + 5 > raw.len() {
1251                        return Err(ErrorKind::InvalidUnicodeEscape);
1252                    }
1253                    let cp = parse_hex4(&raw[i + 1..i + 5])?;
1254                    i += 5;
1255                    if (0xD800..=0xDBFF).contains(&cp) {
1256                        if i + 6 > raw.len() || raw[i] != b'\\' || raw[i + 1] != b'u' {
1257                            return Err(ErrorKind::UnpairedSurrogate);
1258                        }
1259                        let low = parse_hex4(&raw[i + 2..i + 6])?;
1260                        if !(0xDC00..=0xDFFF).contains(&low) {
1261                            return Err(ErrorKind::UnpairedSurrogate);
1262                        }
1263                        i += 6;
1264                    } else if (0xDC00..=0xDFFF).contains(&cp) {
1265                        return Err(ErrorKind::UnpairedSurrogate);
1266                    }
1267                }
1268                _ => return Err(ErrorKind::InvalidEscape),
1269            }
1270        } else if b < 0x20 {
1271            return Err(ErrorKind::ControlCharInString);
1272        } else {
1273            i += 1;
1274        }
1275    }
1276    Ok(())
1277}
1278
1279fn parse_hex4(bytes: &[u8]) -> Result<u32, ErrorKind> {
1280    let mut v: u32 = 0;
1281    for &b in bytes {
1282        let d = match b {
1283            b'0'..=b'9' => b - b'0',
1284            b'a'..=b'f' => b - b'a' + 10,
1285            b'A'..=b'F' => b - b'A' + 10,
1286            _ => return Err(ErrorKind::InvalidUnicodeEscape),
1287        };
1288        v = (v << 4) | u32::from(d);
1289    }
1290    Ok(v)
1291}