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