use core::marker::PhantomData;
use crate::error::{ErrorCode, PResult};
use crate::json::traits::{Read, ReadArray, ReadEnum, ReadObject};
use crate::num::atof::{parse_float, scan_number};
use crate::num::atoi::{parse_i64, parse_u64, reject_float_tail};
use crate::options::{Options, Standard};
use crate::swar::{escape_mask, find_byte, first_match, load_u64, needs_escape};
use crate::traits::{Fields, Keys};
pub const MAX_DEPTH: u32 = 256;
pub struct Parser<'de, O: Options = Standard> {
data: &'de [u8],
idx: usize,
depth: u32,
error_key: Option<&'static str>,
options: PhantomData<fn() -> O>,
}
impl<'de> Parser<'de> {
#[inline]
pub fn new(input: &'de str) -> Self {
Self::with_options(input)
}
}
impl<'de, O: Options> Parser<'de, O> {
#[inline]
pub fn with_options(input: &'de str) -> Self {
Parser {
data: input.as_bytes(),
idx: 0,
depth: 0,
error_key: None,
options: PhantomData,
}
}
#[inline(always)]
pub fn position(&self) -> usize {
self.idx
}
#[inline(always)]
pub fn error_key(&self) -> Option<&'static str> {
self.error_key
}
#[inline(always)]
pub fn set_error_key(&mut self, key: &'static str) {
self.error_key = Some(key);
}
#[inline]
pub fn rewind(&mut self, to: usize) {
self.idx = to.min(self.idx);
self.error_key = None;
}
#[inline(always)]
pub fn rest(&self) -> &'de [u8] {
&self.data[self.idx..]
}
#[inline(always)]
fn remaining(&self) -> usize {
self.data.len() - self.idx
}
#[inline(always)]
pub(crate) fn peek(&self) -> Option<u8> {
self.data.get(self.idx).copied()
}
#[inline(always)]
pub fn skip_ws(&mut self) {
self.idx = skip_ws_at::<O>(self.data, self.idx);
}
#[inline(always)]
pub fn try_byte(&mut self, b: u8) -> bool {
if self.idx < self.data.len() && self.data[self.idx] == b {
self.idx += 1;
true
} else {
false
}
}
#[inline(always)]
pub fn expect(&mut self, b: u8, code: ErrorCode) -> PResult<()> {
if self.idx < self.data.len() && self.data[self.idx] == b {
self.idx += 1;
Ok(())
} else if self.idx >= self.data.len() {
Err(ErrorCode::UnexpectedEnd)
} else {
Err(code)
}
}
#[inline(always)]
pub fn colon(&mut self) -> PResult<()> {
self.skip_ws();
self.expect(b':', ErrorCode::ExpectedColon)?;
self.skip_ws();
Ok(())
}
#[inline(always)]
pub(crate) fn comma_or_close(&mut self, close: u8) -> PResult<bool> {
self.skip_ws();
if self.try_byte(b',') {
self.skip_ws();
return Ok(true);
}
if self.try_byte(close) {
return Ok(false);
}
Err(if self.idx >= self.data.len() {
ErrorCode::UnexpectedEnd
} else {
ErrorCode::ExpectedComma
})
}
#[inline(always)]
pub(crate) fn enter(&mut self) -> PResult<()> {
self.depth += 1;
if self.depth > MAX_DEPTH {
Err(ErrorCode::ExceededMaxDepth)
} else {
Ok(())
}
}
#[inline(always)]
pub(crate) fn leave(&mut self) {
self.depth -= 1;
}
#[inline(always)]
pub fn match_key(&mut self, key: &'static str) -> bool {
let k = key.as_bytes();
let n = k.len();
let i = self.idx;
if i + n < self.data.len() && self.data[i + n] == b'"' && &self.data[i..i + n] == k {
self.idx = i + n + 1;
true
} else {
false
}
}
pub fn read_object<T: ReadObject<'de>>(&mut self, value: &mut T) -> PResult<()> {
self.skip_ws();
let open = self.idx;
self.expect(b'{', ErrorCode::ExpectedBrace)?;
self.enter()?;
self.skip_ws();
let mut seen = 0u64;
if self.try_byte(b'}') {
self.leave();
return self.require_fields::<T>(seen, open);
}
let map = T::MAP;
let n = map.n as usize;
loop {
self.expect(b'"', ErrorCode::ExpectedQuote)?;
let index = map.lookup(T::KEYS, self.rest());
let matched = if index < n {
T::read_field(value, index, self)?
} else {
false
};
if Fields::<O, T>::TRACK && matched {
seen |= Fields::<O, T>::seen(index);
}
if !matched {
if O::ERROR_ON_UNKNOWN_KEYS {
let key = self.idx;
self.skip_string_body()?;
self.idx = key;
return Err(ErrorCode::UnknownKey);
}
self.skip_unknown_member()?;
}
if !self.comma_or_close(b'}')? {
self.leave();
return self.require_fields::<T>(seen, open);
}
}
}
#[inline]
fn require_fields<T: Keys>(&mut self, seen: u64, open: usize) -> PResult<()> {
let mask = Fields::<O, T>::MASK;
if seen & mask != mask {
self.idx = open;
self.error_key = Fields::<O, T>::missing(seen);
return Err(ErrorCode::MissingKey);
}
Ok(())
}
fn skip_unknown_member(&mut self) -> PResult<()> {
self.skip_string_body()?;
self.colon()?;
self.skip_value()
}
pub fn read_enum<T: ReadEnum<'de>>(&mut self, value: &mut T) -> PResult<()> {
self.skip_ws();
match self.peek() {
Some(b'"') => {
self.idx += 1;
self.dispatch_variant(value, T::read_name)
}
Some(b'{') => {
let open = self.idx;
self.idx += 1;
self.enter()?;
self.skip_ws();
if self.peek() == Some(b'}') {
self.idx = open;
return Err(ErrorCode::ExpectedVariant);
}
self.expect(b'"', ErrorCode::ExpectedQuote)?;
self.dispatch_variant(value, T::read_payload)?;
if self.comma_or_close(b'}')? {
self.idx = open;
return Err(ErrorCode::ExpectedVariant);
}
self.leave();
Ok(())
}
Some(_) => Err(ErrorCode::ExpectedVariant),
None => Err(ErrorCode::UnexpectedEnd),
}
}
#[inline]
fn dispatch_variant<T, F>(&mut self, value: &mut T, take: F) -> PResult<()>
where
T: ReadEnum<'de>,
F: FnOnce(&mut T, usize, &mut Self) -> PResult<bool>,
{
let map = T::MAP;
let at = self.idx;
let index = map.lookup(T::VARIANTS, self.rest());
if index < map.n as usize && take(value, index, self)? {
return Ok(());
}
self.idx = at;
self.skip_string_body()?;
self.idx = at;
Err(ErrorCode::UnknownVariant)
}
#[inline]
pub fn read_array<T: ReadArray<'de>>(&mut self, value: &mut T) -> PResult<()> {
let count = self.read_seq(|p, i| value.read_element(i, p))?;
if count != T::LEN {
return Err(ErrorCode::ArrayLengthMismatch);
}
Ok(())
}
#[inline]
pub fn read_seq<F>(&mut self, mut element: F) -> PResult<usize>
where
F: FnMut(&mut Self, usize) -> PResult<()>,
{
self.skip_ws();
self.expect(b'[', ErrorCode::ExpectedBracket)?;
self.enter()?;
self.skip_ws();
if self.try_byte(b']') {
self.leave();
return Ok(0);
}
let mut count = 0usize;
loop {
element(self, count)?;
count += 1;
if !self.comma_or_close(b']')? {
self.leave();
return Ok(count);
}
}
}
#[inline]
pub fn read_map<F>(&mut self, mut entry: F) -> PResult<()>
where
F: FnMut(&mut Self, JsonStr<'de>) -> PResult<()>,
{
self.skip_ws();
self.expect(b'{', ErrorCode::ExpectedBrace)?;
self.enter()?;
self.skip_ws();
if self.try_byte(b'}') {
self.leave();
return Ok(());
}
loop {
self.expect(b'"', ErrorCode::ExpectedQuote)?;
let key = self.read_string_body()?;
self.colon()?;
entry(self, key)?;
if !self.comma_or_close(b'}')? {
self.leave();
return Ok(());
}
}
}
#[inline]
pub fn read_bool(&mut self) -> PResult<bool> {
match self.peek() {
Some(b't') => {
self.expect_lit(b"true", ErrorCode::ExpectedTrue)?;
Ok(true)
}
Some(b'f') => {
self.expect_lit(b"false", ErrorCode::ExpectedFalse)?;
Ok(false)
}
Some(_) => Err(ErrorCode::UnexpectedCharacter),
None => Err(ErrorCode::UnexpectedEnd),
}
}
#[inline(always)]
pub(crate) fn expect_lit(&mut self, lit: &[u8], code: ErrorCode) -> PResult<()> {
let n = lit.len();
if self.remaining() >= n && &self.data[self.idx..self.idx + n] == lit {
self.idx += n;
Ok(())
} else {
Err(code)
}
}
#[inline(always)]
pub fn try_null(&mut self) -> PResult<bool> {
if self.peek() == Some(b'n') {
self.expect_lit(b"null", ErrorCode::ExpectedNull)?;
Ok(true)
} else {
Ok(false)
}
}
#[inline]
pub fn read_u64(&mut self) -> PResult<u64> {
let v = parse_u64(self.data, &mut self.idx)?;
reject_float_tail(self.data, self.idx)?;
Ok(v)
}
#[inline]
pub fn read_i64(&mut self) -> PResult<i64> {
let v = parse_i64(self.data, &mut self.idx)?;
reject_float_tail(self.data, self.idx)?;
Ok(v)
}
#[inline]
pub fn read_f64(&mut self) -> PResult<f64> {
parse_float::<f64>(self.data, &mut self.idx)
}
#[inline]
pub fn read_f32(&mut self) -> PResult<f32> {
parse_float::<f32>(self.data, &mut self.idx)
}
pub fn read_u128(&mut self) -> PResult<u128> {
let n = self.data.len();
let mut i = self.idx;
if i >= n || !self.data[i].is_ascii_digit() {
return Err(ErrorCode::ExpectedNumber);
}
if self.data[i] == b'0' {
i += 1;
if i < n && self.data[i].is_ascii_digit() {
return Err(ErrorCode::InvalidNumber);
}
self.idx = i;
reject_float_tail(self.data, i)?;
return Ok(0);
}
let mut v: u128 = 0;
while i < n {
let c = self.data[i].wrapping_sub(b'0');
if c >= 10 {
break;
}
v = v
.checked_mul(10)
.and_then(|x| x.checked_add(c as u128))
.ok_or(ErrorCode::NumberOutOfRange)?;
i += 1;
}
self.idx = i;
reject_float_tail(self.data, i)?;
Ok(v)
}
pub fn read_i128(&mut self) -> PResult<i128> {
let negative = self.peek() == Some(b'-');
if negative {
self.idx += 1;
}
let magnitude = self.read_u128()?;
if negative {
if magnitude > (i128::MAX as u128) + 1 {
return Err(ErrorCode::NumberOutOfRange);
}
Ok((magnitude as i128).wrapping_neg())
} else {
if magnitude > i128::MAX as u128 {
return Err(ErrorCode::NumberOutOfRange);
}
Ok(magnitude as i128)
}
}
#[inline]
pub fn read_number_str(&mut self) -> PResult<&'de str> {
let start = self.idx;
scan_number(self.data, &mut self.idx)?;
Ok(unsafe { core::str::from_utf8_unchecked(&self.data[start..self.idx]) })
}
#[inline(always)]
fn scan_body(&mut self, from: usize) -> PResult<::core::result::Result<&'de str, usize>> {
match scan_string(self.data, from) {
Some((pos, b'"')) => {
self.idx = pos + 1;
Ok(Ok(unsafe {
core::str::from_utf8_unchecked(&self.data[from..pos])
}))
}
Some((pos, b'\\')) => Ok(Err(pos)),
Some(_) => Err(ErrorCode::ControlCharacterInString),
None => Err(ErrorCode::UnexpectedEnd),
}
}
#[inline]
pub fn read_string(&mut self) -> PResult<JsonStr<'de>> {
self.expect(b'"', ErrorCode::ExpectedQuote)?;
self.read_string_body()
}
#[inline]
pub fn read_string_body(&mut self) -> PResult<JsonStr<'de>> {
let start = self.idx;
match self.scan_body(start)? {
Ok(s) => Ok(JsonStr::Borrowed(s)),
Err(first) => {
let mut out = String::new();
self.unescape_into(start, first, &mut out)?;
Ok(JsonStr::Owned(out))
}
}
}
#[inline]
pub fn read_string_into(&mut self, out: &mut String) -> PResult<()> {
self.expect(b'"', ErrorCode::ExpectedQuote)?;
let start = self.idx;
match self.scan_body(start)? {
Ok(s) => {
out.clear();
out.push_str(s);
Ok(())
}
Err(first) => {
out.clear();
self.unescape_into(start, first, out)
}
}
}
#[inline]
pub fn read_str(&mut self) -> PResult<&'de str> {
self.expect(b'"', ErrorCode::ExpectedQuote)?;
let start = self.idx;
match self.scan_body(start)? {
Ok(s) => Ok(s),
Err(_) => Err(ErrorCode::EscapeInBorrowedString),
}
}
fn unescape_into(&mut self, start: usize, first: usize, out: &mut String) -> PResult<()> {
let bytes = unsafe { out.as_mut_vec() };
bytes.extend_from_slice(&self.data[start..first]);
let mut i = self.expand_escape(first + 1, bytes)?;
loop {
let stop = match scan_string(self.data, i) {
Some((pos, _)) => pos,
None => return Err(ErrorCode::UnexpectedEnd),
};
bytes.extend_from_slice(&self.data[i..stop]);
match self.data[stop] {
b'"' => {
self.idx = stop + 1;
return Ok(());
}
b'\\' => {
i = self.expand_escape(stop + 1, bytes)?;
}
_ => return Err(ErrorCode::ControlCharacterInString),
}
}
}
fn expand_escape(&self, i: usize, out: &mut Vec<u8>) -> PResult<usize> {
let c = *self.data.get(i).ok_or(ErrorCode::UnexpectedEnd)?;
let simple = match c {
b'"' => b'"',
b'\\' => b'\\',
b'/' => b'/',
b'b' => 0x08,
b'f' => 0x0C,
b'n' => b'\n',
b'r' => b'\r',
b't' => b'\t',
b'u' => {
let (ch, next) = self.read_unicode_escape(i + 1)?;
let mut buf = [0u8; 4];
out.extend_from_slice(ch.encode_utf8(&mut buf).as_bytes());
return Ok(next);
}
_ => return Err(ErrorCode::InvalidEscape),
};
out.push(simple);
Ok(i + 1)
}
fn read_unicode_escape(&self, i: usize) -> PResult<(char, usize)> {
let hi = self.read_hex4(i)?;
let mut next = i + 4;
if (0xD800..0xDC00).contains(&hi) {
if self.data.get(next) != Some(&b'\\') || self.data.get(next + 1) != Some(&b'u') {
return Err(ErrorCode::InvalidSurrogate);
}
let lo = self.read_hex4(next + 2)?;
if !(0xDC00..0xE000).contains(&lo) {
return Err(ErrorCode::InvalidSurrogate);
}
next += 6;
let cp = 0x1_0000 + ((hi - 0xD800) << 10) + (lo - 0xDC00);
let ch = char::from_u32(cp).ok_or(ErrorCode::InvalidSurrogate)?;
return Ok((ch, next));
}
if (0xDC00..0xE000).contains(&hi) {
return Err(ErrorCode::InvalidSurrogate);
}
let ch = char::from_u32(hi).ok_or(ErrorCode::InvalidSurrogate)?;
Ok((ch, next))
}
#[inline]
fn read_hex4(&self, i: usize) -> PResult<u32> {
if i + 4 > self.data.len() {
return Err(ErrorCode::UnexpectedEnd);
}
let mut v = 0u32;
for k in 0..4 {
let d = match self.data[i + k] {
c @ b'0'..=b'9' => (c - b'0') as u32,
c @ b'a'..=b'f' => (c - b'a' + 10) as u32,
c @ b'A'..=b'F' => (c - b'A' + 10) as u32,
_ => return Err(ErrorCode::InvalidEscape),
};
v = (v << 4) | d;
}
Ok(v)
}
fn skip_string_body(&mut self) -> PResult<()> {
let mut i = self.idx;
loop {
match scan_string(self.data, i) {
Some((pos, b'"')) => {
self.idx = pos + 1;
return Ok(());
}
Some((pos, b'\\')) => {
i = pos + 2;
if i > self.data.len() {
return Err(ErrorCode::UnexpectedEnd);
}
}
Some(_) => return Err(ErrorCode::ControlCharacterInString),
None => return Err(ErrorCode::UnexpectedEnd),
}
}
}
pub fn skip_value(&mut self) -> PResult<()> {
self.skip_ws();
match self.peek() {
Some(b'{') => {
self.idx += 1;
self.enter()?;
self.skip_ws();
if self.try_byte(b'}') {
self.leave();
return Ok(());
}
loop {
self.expect(b'"', ErrorCode::ExpectedQuote)?;
self.skip_string_body()?;
self.colon()?;
self.skip_value()?;
if !self.comma_or_close(b'}')? {
self.leave();
return Ok(());
}
}
}
Some(b'[') => {
self.idx += 1;
self.enter()?;
self.skip_ws();
if self.try_byte(b']') {
self.leave();
return Ok(());
}
loop {
self.skip_value()?;
if !self.comma_or_close(b']')? {
self.leave();
return Ok(());
}
}
}
_ => self.skip_scalar(),
}
}
#[inline]
pub(crate) fn skip_scalar(&mut self) -> PResult<()> {
match self.peek() {
Some(b'"') => {
self.idx += 1;
self.skip_string_body()
}
Some(b't') => self.expect_lit(b"true", ErrorCode::ExpectedTrue),
Some(b'f') => self.expect_lit(b"false", ErrorCode::ExpectedFalse),
Some(b'n') => self.expect_lit(b"null", ErrorCode::ExpectedNull),
Some(c) if c == b'-' || c.is_ascii_digit() => {
let mut i = self.idx;
let n = self.data.len();
while i < n {
match self.data[i] {
b'0'..=b'9' | b'-' | b'+' | b'.' | b'e' | b'E' => i += 1,
_ => break,
}
}
self.idx = i;
Ok(())
}
None => Err(ErrorCode::UnexpectedEnd),
Some(_) => Err(ErrorCode::UnexpectedCharacter),
}
}
#[inline]
pub fn finish(&mut self) -> PResult<()> {
self.skip_ws();
if self.idx == self.data.len() {
Ok(())
} else {
Err(ErrorCode::TrailingContent)
}
}
#[inline(always)]
pub fn read<T: Read<'de>>(&mut self, value: &mut T) -> PResult<()> {
value.read(self)
}
}
#[inline(always)]
pub(crate) const fn is_ws(c: u8) -> bool {
matches!(c, b' ' | b'\t' | b'\n' | b'\r')
}
#[inline(always)]
pub(crate) const fn scalar_byte(c: u8) -> bool {
c.is_ascii_alphanumeric() || matches!(c, b'-' | b'+' | b'.')
}
#[inline(always)]
pub(crate) fn skip_ws_at<O: Options>(data: &[u8], at: usize) -> usize {
let mut i = at;
while i < data.len() {
match data[i] {
c if is_ws(c) => i += 1,
b'/' if O::ALLOW_COMMENTS => match skip_comment(data, i) {
Some(after) => i = after,
None => break,
},
_ => break,
}
}
i
}
#[inline]
pub(crate) fn skip_comment(data: &[u8], at: usize) -> Option<usize> {
let body = at + 2;
match data.get(at + 1)? {
b'/' => Some(find_byte(data, body, b'\n').unwrap_or(data.len())),
b'*' => {
let end = data.get(body..)?.windows(2).position(|w| w == b"*/")?;
Some(body + end + 2)
}
_ => None,
}
}
pub enum JsonStr<'de> {
Borrowed(&'de str),
Owned(String),
}
impl<'de> JsonStr<'de> {
#[inline(always)]
pub fn as_str(&self) -> &str {
match self {
JsonStr::Borrowed(s) => s,
JsonStr::Owned(s) => s,
}
}
#[inline]
pub fn into_string(self) -> String {
match self {
JsonStr::Borrowed(s) => s.to_owned(),
JsonStr::Owned(s) => s,
}
}
}
#[inline(always)]
fn scan_string(data: &[u8], from: usize) -> Option<(usize, u8)> {
let n = data.len();
let mut i = from;
while i + 8 <= n {
let m = escape_mask(unsafe { load_u64(data, i) });
if m != 0 {
let pos = i + first_match(m);
return Some((pos, data[pos]));
}
i += 8;
}
while i < n {
let c = data[i];
if needs_escape(c) {
return Some((i, c));
}
i += 1;
}
None
}