use crate::error::{Error, ErrorKind, Position};
use crate::event::{Event, JsonNum, JsonStr, MAX_INPUT_LEN};
const I64_MIN_MAGNITUDE: u64 = (i64::MAX as u64) + 1;
#[inline]
fn i64_from_unsigned_magnitude(acc: u64, negative: bool) -> Result<i64, ()> {
if negative {
if acc <= I64_MIN_MAGNITUDE {
return Ok(0i64.wrapping_sub_unsigned(acc));
}
return Err(());
}
i64::try_from(acc).map_err(|_| ())
}
const I128_MIN_MAGNITUDE: u128 = (i128::MAX as u128) + 1;
const U128_FAST_DIGITS: u32 = 38;
pub const DEFAULT_MAX_DEPTH: usize = 128;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[allow(clippy::redundant_pub_crate)]
pub(crate) enum Frame {
Array,
Object,
}
#[derive(Debug)]
#[allow(clippy::redundant_pub_crate)]
pub(crate) struct Stack<const MAX_DEPTH: usize> {
frames: [Frame; MAX_DEPTH],
len: usize,
}
impl<const MAX_DEPTH: usize> Stack<MAX_DEPTH> {
pub(crate) const fn new() -> Self {
Self {
frames: [Frame::Array; MAX_DEPTH],
len: 0,
}
}
pub(crate) const fn push(&mut self, frame: Frame) -> Result<(), ()> {
if self.len >= MAX_DEPTH {
return Err(());
}
self.frames[self.len] = frame;
self.len += 1;
Ok(())
}
pub(crate) const fn pop(&mut self) -> Option<Frame> {
if self.len == 0 {
None
} else {
self.len -= 1;
Some(self.frames[self.len])
}
}
pub(crate) const fn top(&self) -> Option<Frame> {
if self.len == 0 {
None
} else {
Some(self.frames[self.len - 1])
}
}
pub(crate) const fn len(&self) -> usize {
self.len
}
pub(crate) const fn truncate(&mut self, new_len: usize) {
if new_len <= self.len {
self.len = new_len;
}
}
}
enum ObjectPeek {
Close,
Quote,
Comma,
Other,
}
#[derive(Debug)]
pub struct Lexer<'input, const MAX_DEPTH: usize = DEFAULT_MAX_DEPTH> {
input: &'input [u8],
offset: usize,
pub(crate) stack: Stack<MAX_DEPTH>,
}
#[derive(Copy, Clone, Debug)]
pub struct Checkpoint {
offset: usize,
stack_len: usize,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ValueKind {
Object,
Array,
String,
Number,
True,
False,
Null,
}
impl<'input, const MAX_DEPTH: usize> Lexer<'input, MAX_DEPTH> {
#[must_use]
pub const fn new(input: &'input [u8]) -> Self {
assert!(input.len() <= MAX_INPUT_LEN, "input exceeds MAX_INPUT_LEN");
Self {
input,
offset: 0,
stack: Stack::new(),
}
}
#[must_use]
pub const fn position(&self) -> Position {
compute_position(self.input, self.offset)
}
#[must_use]
pub const fn input(&self) -> &'input [u8] {
self.input
}
#[must_use]
pub const fn offset(&self) -> usize {
self.offset
}
#[must_use]
pub const fn checkpoint(&self) -> Checkpoint {
Checkpoint {
offset: self.offset,
stack_len: self.stack.len(),
}
}
pub const fn restore(&mut self, cp: Checkpoint) {
self.offset = cp.offset;
self.stack.truncate(cp.stack_len);
}
pub fn peek_value_kind(&mut self) -> Result<ValueKind, Error> {
self.skip_whitespace();
let b = self
.peek()
.ok_or_else(|| self.err(ErrorKind::UnexpectedEof))?;
match b {
b'{' => Ok(ValueKind::Object),
b'[' => Ok(ValueKind::Array),
b'"' => Ok(ValueKind::String),
b'-' | b'0'..=b'9' => Ok(ValueKind::Number),
b't' => Ok(ValueKind::True),
b'f' => Ok(ValueKind::False),
b'n' => Ok(ValueKind::Null),
other => Err(self.err(ErrorKind::UnexpectedByte(other))),
}
}
pub fn read_value(&mut self) -> Result<Event, Error> {
self.skip_whitespace();
let b = self
.peek()
.ok_or_else(|| self.err(ErrorKind::UnexpectedEof))?;
match b {
b'{' => {
self.bump();
self.push_frame(Frame::Object)?;
Ok(Event::StartObject)
}
b'[' => {
self.bump();
self.push_frame(Frame::Array)?;
Ok(Event::StartArray)
}
b'"' => self.read_string().map(Event::String),
b't' => self.read_keyword(b"true", Event::Bool(true)),
b'f' => self.read_keyword(b"false", Event::Bool(false)),
b'n' => self.read_keyword(b"null", Event::Null),
b'-' | b'0'..=b'9' => self.read_number().map(Event::Number),
other => Err(self.err(ErrorKind::UnexpectedByte(other))),
}
}
pub(crate) fn pop_frame(&mut self, expected: Frame) -> Result<(), Error> {
let popped = self
.stack
.pop()
.ok_or_else(|| self.err(ErrorKind::UnexpectedByte(b']')))?;
if popped != expected {
return Err(self.err(ErrorKind::TypeMismatch));
}
Ok(())
}
pub(crate) fn push_frame(&mut self, frame: Frame) -> Result<(), Error> {
self.stack
.push(frame)
.map_err(|()| self.err(ErrorKind::DepthLimitExceeded))
}
pub(crate) fn read_keyword(&mut self, kw: &[u8], event: Event) -> Result<Event, Error> {
for &expected in kw {
match self.peek() {
Some(b) if b == expected => self.bump(),
Some(b) => return Err(self.err(ErrorKind::UnexpectedByte(b))),
None => return Err(self.err(ErrorKind::UnexpectedEof)),
}
}
Ok(event)
}
pub fn read_string(&mut self) -> Result<JsonStr, Error> {
self.read_string_inner(true)
}
pub fn read_string_no_validate(&mut self) -> Result<JsonStr, Error> {
self.read_string_inner(false)
}
fn read_string_inner(&mut self, validate: bool) -> Result<JsonStr, Error> {
debug_assert_eq!(self.peek(), Some(b'"'));
self.bump(); let start = self.offset;
let mut has_escapes = false;
loop {
let b = self
.peek()
.ok_or_else(|| self.err(ErrorKind::UnexpectedEof))?;
match b {
b'"' => {
let end = self.offset;
self.bump(); if validate && has_escapes {
let raw = &self.input[start..end];
validate_escapes(raw).map_err(|kind| self.err(kind))?;
}
#[allow(clippy::cast_possible_truncation)]
return Ok(JsonStr::new(start as u32, end as u32, has_escapes));
}
b'\\' => {
has_escapes = true;
self.bump();
match self.peek() {
Some(b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't') => {
self.bump();
}
Some(b'u') => {
self.bump();
for _ in 0..4 {
match self.peek() {
Some(b) if b.is_ascii_hexdigit() => self.bump(),
Some(b) => return Err(self.err(ErrorKind::UnexpectedByte(b))),
None => return Err(self.err(ErrorKind::UnexpectedEof)),
}
}
}
Some(_) => return Err(self.err(ErrorKind::InvalidEscape)),
None => return Err(self.err(ErrorKind::UnexpectedEof)),
}
}
0..=0x1F => return Err(self.err(ErrorKind::ControlCharInString)),
0x20..=0x7F => self.scan_ascii_string_run(),
_ => self.consume_utf8_multibyte()?,
}
}
}
#[inline]
pub fn read_number(&mut self) -> Result<JsonNum, Error> {
let start = self.offset;
if self.peek() == Some(b'-') {
self.bump();
}
match self.peek() {
Some(b'0') => {
self.bump();
}
Some(b'1'..=b'9') => {
self.bump();
self.scan_digit_run();
}
Some(b) => return Err(self.err(ErrorKind::UnexpectedByte(b))),
None => return Err(self.err(ErrorKind::UnexpectedEof)),
}
if self.peek() == Some(b'.') {
self.bump();
let frac_start = self.offset;
self.scan_digit_run();
if self.offset == frac_start {
return Err(self.err(ErrorKind::InvalidNumber));
}
}
if matches!(self.peek(), Some(b'e' | b'E')) {
self.bump();
if matches!(self.peek(), Some(b'+' | b'-')) {
self.bump();
}
let exp_start = self.offset;
self.scan_digit_run();
if self.offset == exp_start {
return Err(self.err(ErrorKind::InvalidNumber));
}
}
#[allow(clippy::cast_possible_truncation)]
let result = JsonNum::new(start as u32, self.offset as u32);
Ok(result)
}
pub fn parse_i64_value(&mut self) -> Result<i64, Error> {
let start = self.offset;
let bytes = self.input;
let mut i = start;
let negative = matches!(bytes.get(i), Some(&b'-'));
if negative {
i += 1;
}
match bytes.get(i).copied() {
Some(b'0') => {
i += 1;
self.offset = i;
if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
return Err(self.err(ErrorKind::ExpectedNumber));
}
Ok(0)
}
Some(b'1'..=b'9') => self.parse_i64_digits(i, negative),
Some(b) => {
self.offset = i;
Err(self.err(ErrorKind::UnexpectedByte(b)))
}
None => {
self.offset = i;
Err(self.err(ErrorKind::UnexpectedEof))
}
}
}
fn parse_i64_digits(&mut self, start: usize, negative: bool) -> Result<i64, Error> {
let bytes = self.input;
let end = bytes.len();
let mut i = start;
let mut acc: u64 = 0;
let mut count: u32 = 0;
while i < end {
let d = bytes[i].wrapping_sub(b'0');
if d >= 10 {
break;
}
if count < 19 {
acc = acc * 10 + u64::from(d);
} else {
acc = acc
.checked_mul(10)
.and_then(|v| v.checked_add(u64::from(d)))
.ok_or_else(|| {
self.offset = i;
self.err(ErrorKind::NumberOutOfRange)
})?;
}
i += 1;
count += 1;
}
self.offset = i;
if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
return Err(self.err(ErrorKind::ExpectedNumber));
}
i64_from_unsigned_magnitude(acc, negative)
.map_err(|()| self.err(ErrorKind::NumberOutOfRange))
}
pub fn parse_i128_value(&mut self) -> Result<i128, Error> {
let start = self.offset;
let bytes = self.input;
let end = bytes.len();
let mut i = start;
let negative = matches!(bytes.get(i), Some(&b'-'));
if negative {
i += 1;
}
let digits_start = i;
match bytes.get(i).copied() {
Some(b'0') => i += 1,
Some(b'1'..=b'9') => {
let mut acc: u128 = 0;
let mut count: u32 = 0;
while i < end {
let d = bytes[i].wrapping_sub(b'0');
if d >= 10 {
break;
}
if count < U128_FAST_DIGITS {
acc = acc * 10 + u128::from(d);
} else {
acc = acc
.checked_mul(10)
.and_then(|v| v.checked_add(u128::from(d)))
.ok_or_else(|| {
self.offset = i;
self.err(ErrorKind::NumberOutOfRange)
})?;
}
i += 1;
count += 1;
}
if i == digits_start {
self.offset = i;
return Err(self.err(ErrorKind::InvalidNumber));
}
self.offset = i;
if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
return Err(self.err(ErrorKind::ExpectedNumber));
}
if negative {
if acc <= I128_MIN_MAGNITUDE {
return Ok(0i128.wrapping_sub_unsigned(acc));
}
return Err(self.err(ErrorKind::NumberOutOfRange));
}
if let Ok(n) = i128::try_from(acc) {
return Ok(n);
}
return Err(self.err(ErrorKind::NumberOutOfRange));
}
Some(b) => {
self.offset = i;
return Err(self.err(ErrorKind::UnexpectedByte(b)));
}
None => {
self.offset = i;
return Err(self.err(ErrorKind::UnexpectedEof));
}
}
self.offset = i;
if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
return Err(self.err(ErrorKind::ExpectedNumber));
}
Ok(0)
}
pub fn parse_u128_value(&mut self) -> Result<u128, Error> {
let start = self.offset;
let bytes = self.input;
let end = bytes.len();
let mut i = start;
if matches!(bytes.get(i), Some(&b'-')) {
self.offset = i;
return Err(self.err(ErrorKind::NumberOutOfRange));
}
let digits_start = i;
match bytes.get(i).copied() {
Some(b'0') => i += 1,
Some(b'1'..=b'9') => {
let mut acc: u128 = 0;
let mut count: u32 = 0;
while i < end {
let d = bytes[i].wrapping_sub(b'0');
if d >= 10 {
break;
}
if count < U128_FAST_DIGITS {
acc = acc * 10 + u128::from(d);
} else {
acc = acc
.checked_mul(10)
.and_then(|v| v.checked_add(u128::from(d)))
.ok_or_else(|| {
self.offset = i;
self.err(ErrorKind::NumberOutOfRange)
})?;
}
i += 1;
count += 1;
}
if i == digits_start {
self.offset = i;
return Err(self.err(ErrorKind::InvalidNumber));
}
self.offset = i;
if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
return Err(self.err(ErrorKind::ExpectedNumber));
}
return Ok(acc);
}
Some(b) => {
self.offset = i;
return Err(self.err(ErrorKind::UnexpectedByte(b)));
}
None => {
self.offset = i;
return Err(self.err(ErrorKind::UnexpectedEof));
}
}
self.offset = i;
if matches!(bytes.get(i), Some(&b'.' | &b'e' | &b'E')) {
return Err(self.err(ErrorKind::ExpectedNumber));
}
Ok(0)
}
pub fn parse_f64_value(&mut self) -> Result<f64, Error> {
let start = self.offset;
let _span = self.read_number()?;
let end = self.offset;
#[allow(unsafe_code)]
let s = unsafe { core::str::from_utf8_unchecked(&self.input[start..end]) };
let v: f64 = s.parse().map_err(|_| self.err(ErrorKind::InvalidNumber))?;
if v.is_finite() {
Ok(v)
} else {
Err(self.err(ErrorKind::NumberOutOfRange))
}
}
pub fn parse_str_value(&mut self) -> Result<&'input str, Error> {
match self.peek() {
Some(b'"') => self.bump(),
Some(b) => return Err(self.err(ErrorKind::UnexpectedByte(b))),
None => return Err(self.err(ErrorKind::UnexpectedEof)),
}
let start = self.offset;
loop {
let b = self
.peek()
.ok_or_else(|| self.err(ErrorKind::UnexpectedEof))?;
match b {
b'"' => {
let end = self.offset;
self.bump();
let raw = &self.input[start..end];
return Ok(unsafe { core::str::from_utf8_unchecked(raw) });
}
b'\\' => return Err(self.err(ErrorKind::InvalidEscape)),
0..=0x1F => return Err(self.err(ErrorKind::ControlCharInString)),
0x20..=0x7F => self.scan_ascii_string_run(),
_ => self.consume_utf8_multibyte()?,
}
}
}
#[inline]
pub fn array_continue(&mut self, end_byte: u8) -> Result<bool, Error> {
self.skip_whitespace();
match self.peek() {
Some(b) if b == end_byte => {
self.bump();
let frame = if end_byte == b']' {
Frame::Array
} else {
Frame::Object
};
self.pop_frame(frame)?;
Ok(true)
}
Some(b',') => {
self.bump();
self.skip_whitespace();
Ok(false)
}
Some(b) => Err(self.err(ErrorKind::UnexpectedByte(b))),
None => Err(self.err(ErrorKind::UnexpectedEof)),
}
}
fn peek_object(&self) -> ObjectPeek {
match self.peek() {
Some(b'}') => ObjectPeek::Close,
Some(b'"') => ObjectPeek::Quote,
Some(b',') => ObjectPeek::Comma,
Some(_) | None => ObjectPeek::Other,
}
}
fn close_object(&mut self) -> Result<(), Error> {
self.bump();
self.pop_frame(Frame::Object)
}
fn expect_byte(&mut self, expected: u8) -> Result<(), Error> {
match self.peek() {
Some(b) if b == expected => {
self.bump();
Ok(())
}
Some(b) => Err(self.err(ErrorKind::UnexpectedByte(b))),
None => Err(self.err(ErrorKind::UnexpectedEof)),
}
}
fn expect_colon(&mut self) -> Result<(), Error> {
self.skip_whitespace();
self.expect_byte(b':')?;
self.skip_whitespace();
Ok(())
}
fn advance_comma_to_quote(&mut self) -> Result<(), Error> {
self.bump();
self.skip_whitespace();
match self.peek_object() {
ObjectPeek::Quote => Ok(()),
_ => Err(self.unexpected_or_eof()),
}
}
#[inline]
pub fn object_first_key(&mut self) -> Result<Option<&'input str>, Error> {
self.skip_whitespace();
match self.peek_object() {
ObjectPeek::Close => {
self.close_object()?;
Ok(None)
}
ObjectPeek::Quote => {
let key = self.parse_str_value()?;
self.expect_colon()?;
Ok(Some(key))
}
ObjectPeek::Comma | ObjectPeek::Other => Err(self.unexpected_or_eof()),
}
}
#[inline]
pub fn object_first_key_lex(&mut self) -> Result<Option<JsonStr>, Error> {
self.skip_whitespace();
match self.peek_object() {
ObjectPeek::Close => {
self.close_object()?;
Ok(None)
}
ObjectPeek::Quote => {
let key = self.read_string_no_validate()?;
self.expect_colon()?;
Ok(Some(key))
}
ObjectPeek::Comma | ObjectPeek::Other => Err(self.unexpected_or_eof()),
}
}
#[inline]
pub fn object_next_key(&mut self) -> Result<Option<&'input str>, Error> {
self.skip_whitespace();
match self.peek_object() {
ObjectPeek::Close => {
self.close_object()?;
Ok(None)
}
ObjectPeek::Comma => {
self.advance_comma_to_quote()?;
let key = self.parse_str_value()?;
self.expect_colon()?;
Ok(Some(key))
}
ObjectPeek::Quote | ObjectPeek::Other => Err(self.unexpected_or_eof()),
}
}
#[inline]
pub fn object_next_key_lex(&mut self) -> Result<Option<JsonStr>, Error> {
self.skip_whitespace();
match self.peek_object() {
ObjectPeek::Close => {
self.close_object()?;
Ok(None)
}
ObjectPeek::Comma => {
self.advance_comma_to_quote()?;
let key = self.read_string_no_validate()?;
self.expect_colon()?;
Ok(Some(key))
}
ObjectPeek::Quote | ObjectPeek::Other => Err(self.unexpected_or_eof()),
}
}
fn unexpected_or_eof(&self) -> Error {
self.peek().map_or_else(
|| self.err(ErrorKind::UnexpectedEof),
|b| self.err(ErrorKind::UnexpectedByte(b)),
)
}
#[inline]
pub fn array_start(&mut self) -> Result<bool, Error> {
self.skip_whitespace();
match self.peek() {
Some(b'[') => {
self.bump();
self.push_frame(Frame::Array)?;
self.skip_whitespace();
if self.peek() == Some(b']') {
self.bump();
self.pop_frame(Frame::Array)?;
Ok(true)
} else {
Ok(false)
}
}
Some(b) => Err(self.err(ErrorKind::UnexpectedByte(b))),
None => Err(self.err(ErrorKind::UnexpectedEof)),
}
}
#[inline]
pub fn object_start(&mut self) -> Result<(), Error> {
self.skip_whitespace();
match self.peek() {
Some(b'{') => {
self.bump();
self.push_frame(Frame::Object)?;
self.skip_whitespace();
Ok(())
}
Some(b) => Err(self.err(ErrorKind::UnexpectedByte(b))),
None => Err(self.err(ErrorKind::UnexpectedEof)),
}
}
pub fn finish(&mut self) -> Result<(), Error> {
self.skip_whitespace();
if self.peek().is_some() {
Err(self.err(ErrorKind::TrailingData))
} else {
Ok(())
}
}
pub fn skip_value(&mut self) -> Result<(), Error> {
let event = self.read_value()?;
match event {
Event::StartArray => self.skip_array_body(),
Event::StartObject => self.skip_object_body(),
Event::String(_) | Event::Number(_) | Event::Bool(_) | Event::Null => Ok(()),
Event::EndArray | Event::EndObject | Event::Key(_) => {
Err(self.err(ErrorKind::UnexpectedByte(b']')))
}
}
}
fn skip_array_body(&mut self) -> Result<(), Error> {
self.skip_whitespace();
if matches!(self.peek(), Some(b']')) {
self.bump();
return self.pop_frame(Frame::Array);
}
self.skip_value()?;
while !self.array_continue(b']')? {
self.skip_value()?;
}
Ok(())
}
fn skip_object_body(&mut self) -> Result<(), Error> {
let mut key = self.object_first_key()?;
while key.is_some() {
self.skip_value()?;
key = self.object_next_key()?;
}
Ok(())
}
#[inline]
fn scan_ascii_string_run(&mut self) {
#[cfg(all(target_arch = "x86_64", not(bourne_no_simd)))]
unsafe {
self.scan_ascii_string_run_sse2();
}
#[cfg(not(all(target_arch = "x86_64", not(bourne_no_simd))))]
self.scan_ascii_string_run_scalar();
}
#[inline]
fn scan_ascii_string_run_scalar(&mut self) {
let bytes = self.input;
let mut i = self.offset;
let end = bytes.len();
while i < end {
let b = bytes[i];
if b == b'"' || b == b'\\' || !(0x20..0x80).contains(&b) {
break;
}
i += 1;
}
self.offset = i;
}
#[cfg(all(target_arch = "x86_64", not(bourne_no_simd)))]
#[target_feature(enable = "sse2")]
#[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
unsafe fn scan_ascii_string_run_sse2(&mut self) {
use core::arch::x86_64::{
_mm_cmpeq_epi8, _mm_cmplt_epi8, _mm_loadu_si128, _mm_movemask_epi8, _mm_or_si128,
_mm_set1_epi8,
};
let bytes = self.input;
let end = bytes.len();
let mut i = self.offset;
let quote = _mm_set1_epi8(b'"' as i8);
let backslash = _mm_set1_epi8(b'\\' as i8);
let lt_threshold = _mm_set1_epi8(0x20_i8);
while i + 16 <= end {
let chunk = unsafe { _mm_loadu_si128(bytes.as_ptr().add(i).cast()) };
let m_quote = _mm_cmpeq_epi8(chunk, quote);
let m_back = _mm_cmpeq_epi8(chunk, backslash);
let m_ctrl_or_hi = _mm_cmplt_epi8(chunk, lt_threshold);
let mask = _mm_or_si128(_mm_or_si128(m_quote, m_back), m_ctrl_or_hi);
let bits = _mm_movemask_epi8(mask) as u32;
if bits != 0 {
i += bits.trailing_zeros() as usize;
self.offset = i;
return;
}
i += 16;
}
self.offset = i;
self.scan_ascii_string_run_scalar();
}
#[inline]
fn consume_utf8_multibyte(&mut self) -> Result<(), Error> {
let leading = self
.peek()
.ok_or_else(|| self.err(ErrorKind::InvalidUtf8))?;
let (extra, second_lo, second_hi) =
utf8_leading_byte_info(leading).ok_or_else(|| self.err(ErrorKind::InvalidUtf8))?;
self.bump();
match self.peek() {
Some(b) if b >= second_lo && b <= second_hi => self.bump(),
_ => return Err(self.err(ErrorKind::InvalidUtf8)),
}
for _ in 1..extra {
match self.peek() {
Some(0x80..=0xBF) => self.bump(),
_ => return Err(self.err(ErrorKind::InvalidUtf8)),
}
}
Ok(())
}
fn scan_digit_run(&mut self) {
let bytes = self.input;
let mut i = self.offset;
let end = bytes.len();
while i < end {
let b = bytes[i];
if b.wrapping_sub(b'0') >= 10 {
break;
}
i += 1;
}
self.offset = i;
}
pub(crate) fn skip_whitespace(&mut self) {
let bytes = self.input;
let mut i = self.offset;
let end = bytes.len();
while i < end {
let b = bytes[i];
if b == b' ' || b == b'\t' || b == b'\n' || b == b'\r' {
i += 1;
} else {
break;
}
}
self.offset = i;
}
pub(crate) fn peek(&self) -> Option<u8> {
self.input.get(self.offset).copied()
}
pub(crate) fn bump(&mut self) {
debug_assert!(self.offset < self.input.len());
self.offset += 1;
}
pub(crate) const fn err(&self, kind: ErrorKind) -> Error {
Error::new(kind, compute_position(self.input, self.offset))
}
}
#[allow(clippy::cast_possible_truncation)]
const fn compute_position(_input: &[u8], offset: usize) -> Position {
Position::new(offset as u32)
}
#[inline]
const fn utf8_leading_byte_info(b: u8) -> Option<(u8, u8, u8)> {
match b {
0xC2..=0xDF => Some((1, 0x80, 0xBF)),
0xE0 => Some((2, 0xA0, 0xBF)),
0xE1..=0xEC | 0xEE..=0xEF => Some((2, 0x80, 0xBF)),
0xED => Some((2, 0x80, 0x9F)),
0xF0 => Some((3, 0x90, 0xBF)),
0xF1..=0xF3 => Some((3, 0x80, 0xBF)),
0xF4 => Some((3, 0x80, 0x8F)),
_ => None,
}
}
fn validate_escapes(raw: &[u8]) -> Result<(), ErrorKind> {
let mut i = 0;
while i < raw.len() {
let b = raw[i];
if b == b'\\' {
i += 1;
if i >= raw.len() {
return Err(ErrorKind::InvalidEscape);
}
match raw[i] {
b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't' => i += 1,
b'u' => {
if i + 5 > raw.len() {
return Err(ErrorKind::InvalidUnicodeEscape);
}
let cp = parse_hex4(&raw[i + 1..i + 5])?;
i += 5;
if (0xD800..=0xDBFF).contains(&cp) {
if i + 6 > raw.len() || raw[i] != b'\\' || raw[i + 1] != b'u' {
return Err(ErrorKind::UnpairedSurrogate);
}
let low = parse_hex4(&raw[i + 2..i + 6])?;
if !(0xDC00..=0xDFFF).contains(&low) {
return Err(ErrorKind::UnpairedSurrogate);
}
i += 6;
} else if (0xDC00..=0xDFFF).contains(&cp) {
return Err(ErrorKind::UnpairedSurrogate);
}
}
_ => return Err(ErrorKind::InvalidEscape),
}
} else if b < 0x20 {
return Err(ErrorKind::ControlCharInString);
} else {
i += 1;
}
}
Ok(())
}
fn parse_hex4(bytes: &[u8]) -> Result<u32, ErrorKind> {
let mut v: u32 = 0;
for &b in bytes {
let d = match b {
b'0'..=b'9' => b - b'0',
b'a'..=b'f' => b - b'a' + 10,
b'A'..=b'F' => b - b'A' + 10,
_ => return Err(ErrorKind::InvalidUnicodeEscape),
};
v = (v << 4) | u32::from(d);
}
Ok(v)
}