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}