use core::marker::PhantomData;
use crate::beve::header::{self, byte_width, decode_size};
use crate::beve::impls::{Block, NumericBytes};
use crate::beve::traits::{Read, ReadArray, ReadAs, ReadEnum, ReadInternallyTagged, ReadObject};
use crate::error::{ErrorCode, PResult};
use crate::num::atoi::parse_int_text;
use crate::options::{Options, Standard};
use crate::traits::{Fields, resolve_key, resolve_variant};
pub const MAX_DEPTH: u32 = 256;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Key<'de> {
Str(&'de str),
Signed(i128),
Unsigned(u128),
}
#[derive(Clone, Copy)]
struct Deferred {
start: usize,
count: usize,
depth: u32,
}
const RESERVE_LIMIT: usize = 1 << 20;
#[inline]
pub fn cautious<T>(n: usize) -> usize {
match core::mem::size_of::<T>() {
0 => n,
w => n.min(RESERVE_LIMIT / w),
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Typed {
Bools(usize),
Strings(usize),
Fixed(u8, usize),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Int {
Signed(i128),
Unsigned(u128),
}
pub struct Reader<'de, O: Options = Standard> {
data: &'de [u8],
pos: usize,
depth: u32,
error_key: Option<&'static str>,
implied: Option<u8>,
installed: Option<(usize, u8)>,
deferred: Vec<Deferred>,
options: PhantomData<fn() -> O>,
}
impl<'de> Reader<'de> {
#[inline]
pub fn new(data: &'de [u8]) -> Self {
Self::with_options(data)
}
}
impl<'de, O: Options> Reader<'de, O> {
#[inline]
pub fn with_options(data: &'de [u8]) -> Self {
Reader {
data,
pos: 0,
depth: 0,
error_key: None,
deferred: Vec::new(),
implied: None,
installed: None,
options: PhantomData,
}
}
#[inline]
pub(crate) fn with_implied(data: &'de [u8], implied: u8) -> Self {
Reader {
data,
pos: 0,
depth: 0,
error_key: None,
deferred: Vec::new(),
implied: Some(implied),
installed: Some((0, implied)),
options: PhantomData,
}
}
#[inline]
pub fn position(&self) -> usize {
self.pos
}
#[inline]
pub(crate) fn remaining(&self) -> usize {
self.data.len() - self.pos
}
#[inline]
fn honest(&self, n: usize) -> usize {
n.min(self.remaining())
}
#[inline]
pub fn error_key(&self) -> Option<&'static str> {
self.error_key
}
#[inline]
pub fn set_error_key(&mut self, key: &'static str) {
self.error_key = Some(key);
}
#[inline]
pub fn rewind(&mut self, to: usize) {
self.error_key = None;
if to > self.pos {
return;
}
self.pos = to;
self.installed = self.installed.filter(|&(at, _)| at == to);
self.implied = self.installed.map(|(_, h)| h);
}
pub fn finish(&mut self) -> PResult<()> {
if self.pos == self.data.len() {
Ok(())
} else {
Err(ErrorCode::TrailingContent)
}
}
#[inline]
pub fn read<T: Read<'de>>(&mut self, value: &mut T) -> PResult<()> {
value.read(self)
}
#[inline(always)]
pub(crate) fn peek(&self) -> Option<u8> {
match self.implied {
Some(h) => Some(h),
None => self.data.get(self.pos).copied(),
}
}
#[inline(always)]
pub(crate) fn head(&mut self) -> PResult<u8> {
if let Some(h) = self.implied.take() {
return Ok(h);
}
let &b = self.data.get(self.pos).ok_or(ErrorCode::UnexpectedEnd)?;
self.pos += 1;
Ok(b)
}
#[inline]
pub fn take(&mut self, n: usize) -> PResult<&'de [u8]> {
let data = self.data;
let end = self.pos.checked_add(n).ok_or(ErrorCode::UnexpectedEnd)?;
if end > data.len() {
return Err(ErrorCode::UnexpectedEnd);
}
let out = &data[self.pos..end];
self.pos = end;
Ok(out)
}
#[inline]
fn drop_bytes(&mut self, n: usize) -> PResult<()> {
self.take(n).map(|_| ())
}
#[inline]
pub fn size(&mut self) -> PResult<u64> {
decode_size(self.data, &mut self.pos)
}
#[inline]
pub(crate) fn count(&mut self) -> PResult<usize> {
usize::try_from(self.size()?).map_err(|_| ErrorCode::UnexpectedEnd)
}
#[inline(always)]
pub(crate) fn enter(&mut self) -> PResult<()> {
if self.depth >= MAX_DEPTH {
return Err(ErrorCode::ExceededMaxDepth);
}
self.depth += 1;
Ok(())
}
#[inline(always)]
pub(crate) fn nested<R>(&mut self, body: impl FnOnce(&mut Self) -> PResult<R>) -> PResult<R> {
self.enter()?;
let result = body(self);
self.leave();
result
}
#[inline(always)]
fn can_enter(&self) -> bool {
self.depth < MAX_DEPTH
}
#[inline(always)]
fn implying<R>(&mut self, h: u8, body: impl FnOnce(&mut Self) -> PResult<R>) -> PResult<R> {
let outer = self.installed;
self.install(h);
let result = body(self);
self.implied = None;
self.installed = outer;
result
}
#[inline(always)]
fn install(&mut self, h: u8) {
self.implied = Some(h);
self.installed = Some((self.pos, h));
}
#[inline(always)]
pub(crate) fn leave(&mut self) {
debug_assert!(
self.depth > 0,
"structio: `leave` without a matching `enter`, which would disable the nesting limit"
);
self.depth -= 1;
}
fn aligned_head(&mut self) -> PResult<(u8, usize)> {
let inner = self.head()?;
if header::ty(inner) != header::TY_TYPED_ARRAY || header::sub(inner) == header::CAT_OTHER {
return Err(ErrorCode::InvalidHeader);
}
let width = fixed_width(inner)?;
let n = self.count()?;
self.skip_padding(width)?;
Ok((inner, n))
}
fn skip_padding(&mut self, width: usize) -> PResult<()> {
let pad = self.take(1)?[0];
aligned_padding(pad, width)?;
self.drop_bytes(usize::from(pad))
}
fn aligned_pairs(&mut self, class: u8, width: usize) -> PResult<usize> {
if self.head()? != header::ALIGNED_ARRAY {
return Err(ErrorCode::InvalidHeader);
}
if self.head()? != header::complex_components(class) {
return Err(ErrorCode::InvalidHeader);
}
let components = self.count()?;
if components % 2 != 0 {
return Err(ErrorCode::InvalidHeader);
}
self.skip_padding(width)?;
Ok(components / 2)
}
#[inline]
fn have(&self, n: usize) -> PResult<()> {
match self.pos.checked_add(n) {
Some(end) if end <= self.data.len() => Ok(()),
_ => Err(ErrorCode::UnexpectedEnd),
}
}
pub(crate) fn typed_head(&mut self, h: u8) -> PResult<Typed> {
let form = self.typed_preamble(h)?;
if let Typed::Bools(n) = form {
let bytes = n.div_ceil(8);
self.have(bytes)?;
if let Some(last) = bytes.checked_sub(1)
&& let Err(e) = bool_padding(n, self.data[self.pos + last])
{
self.pos += bytes;
return Err(e);
}
}
Ok(form)
}
pub(crate) fn typed_preamble(&mut self, h: u8) -> PResult<Typed> {
match header::sub(h) {
header::CAT_OTHER => match header::count(h) {
header::OTHER_BOOL => Ok(Typed::Bools(self.count()?)),
header::OTHER_STRING => Ok(Typed::Strings(self.count()?)),
header::OTHER_ALIGNED => {
let (inner, n) = self.aligned_head()?;
Ok(Typed::Fixed(inner, n))
}
_ => Err(ErrorCode::InvalidHeader),
},
_ => {
fixed_width(h)?;
Ok(Typed::Fixed(h, self.count()?))
}
}
}
pub(crate) fn complex_head(&mut self) -> PResult<(u8, usize, Option<usize>)> {
let class = self.head()?;
let width =
byte_width(header::sub(class), header::count(class)).ok_or(ErrorCode::InvalidHeader)?;
let pairs = match class & 0b111 {
header::COMPLEX_ONE => None,
header::COMPLEX_MANY => Some(self.count()?),
header::COMPLEX_ALIGNED => Some(self.aligned_pairs(class, width)?),
_ => return Err(ErrorCode::InvalidHeader),
};
Ok((class, width, pairs))
}
pub(crate) fn complex_form(&mut self) -> PResult<Option<u8>> {
if let Some(h) = self.implied.take() {
if header::ty(h) != header::TY_UNDEFINED {
return Err(ErrorCode::ExpectedComplex);
}
return Ok(Some(header::element_of(h)));
}
match self.peek() {
Some(header::COMPLEX) => {
self.head()?;
let (class, _, pairs) = self.complex_head()?;
if pairs.is_some() {
return Err(ErrorCode::ExpectedComplex);
}
Ok(Some(header::element_of(class)))
}
Some(h)
if matches!(
header::ty(h),
header::TY_GENERIC_ARRAY | header::TY_TYPED_ARRAY
) =>
{
Ok(None)
}
Some(_) => {
self.head()?;
Err(ErrorCode::ExpectedComplex)
}
None => Err(ErrorCode::UnexpectedEnd),
}
}
pub(crate) fn complex_pair<T: Read<'de>>(
&mut self,
elem: u8,
re: &mut T,
im: &mut T,
) -> PResult<()> {
self.implying(elem, |r| re.read(r))?;
self.implying(elem, |r| im.read(r))
}
#[inline]
pub fn read_bool(&mut self) -> PResult<bool> {
match self.head()? {
header::TRUE => Ok(true),
header::FALSE => Ok(false),
header::NULL => Err(ErrorCode::ExpectedBool),
h if header::ty(h) == header::TY_NULL_BOOL => Err(ErrorCode::InvalidHeader),
_ => Err(ErrorCode::ExpectedBool),
}
}
#[inline]
pub fn try_null(&mut self) -> PResult<bool> {
match self.peek() {
Some(header::NULL) => {
self.head()?;
Ok(true)
}
Some(_) => Ok(false),
None => Err(ErrorCode::UnexpectedEnd),
}
}
fn read_int(&mut self) -> PResult<Int> {
let h = self.head()?;
if header::ty(h) != header::TY_NUMBER {
return Err(ErrorCode::ExpectedNumber);
}
let cat = header::sub(h);
let width = byte_width(cat, header::count(h)).ok_or(ErrorCode::InvalidHeader)?;
if cat == header::CAT_FLOAT {
return Err(ErrorCode::ExpectedInteger);
}
let bytes = self.take(width)?;
match cat {
header::CAT_UNSIGNED => Ok(Int::Unsigned(le_u128(bytes))),
header::CAT_SIGNED => Ok(Int::Signed(sign_extend(le_u128(bytes), width))),
_ => Err(ErrorCode::ExpectedInteger),
}
}
#[inline]
pub fn read_u64(&mut self) -> PResult<u64> {
match self.read_int()? {
Int::Unsigned(v) => u64::try_from(v).map_err(|_| ErrorCode::NumberOutOfRange),
Int::Signed(v) => u64::try_from(v).map_err(|_| ErrorCode::NumberOutOfRange),
}
}
#[inline]
pub fn read_i64(&mut self) -> PResult<i64> {
match self.read_int()? {
Int::Unsigned(v) => i64::try_from(v).map_err(|_| ErrorCode::NumberOutOfRange),
Int::Signed(v) => i64::try_from(v).map_err(|_| ErrorCode::NumberOutOfRange),
}
}
#[inline]
pub fn read_u128(&mut self) -> PResult<u128> {
match self.read_int()? {
Int::Unsigned(v) => Ok(v),
Int::Signed(v) => u128::try_from(v).map_err(|_| ErrorCode::NumberOutOfRange),
}
}
#[inline]
pub fn read_i128(&mut self) -> PResult<i128> {
match self.read_int()? {
Int::Unsigned(v) => i128::try_from(v).map_err(|_| ErrorCode::NumberOutOfRange),
Int::Signed(v) => Ok(v),
}
}
pub fn read_f64(&mut self) -> PResult<f64> {
let (cat, code, bytes) = self.number_body()?;
widen(cat, code, bytes)
}
pub fn read_f32(&mut self) -> PResult<f32> {
let (cat, code, bytes) = self.number_body()?;
if cat == header::CAT_FLOAT && code == 2 {
return Ok(f32::from_le_bytes(bytes.try_into().expect("four bytes")));
}
widen(cat, code, bytes).map(|v| v as f32)
}
#[inline]
fn number_body(&mut self) -> PResult<(u8, u8, &'de [u8])> {
let h = self.head()?;
if header::ty(h) != header::TY_NUMBER {
return Err(ErrorCode::ExpectedNumber);
}
let cat = header::sub(h);
let code = header::count(h);
let width = header::decodable_width(cat, code)?;
Ok((cat, code, self.take(width)?))
}
#[inline]
pub fn read_str(&mut self) -> PResult<&'de str> {
let h = self.head()?;
if header::ty(h) != header::TY_STRING {
return Err(ErrorCode::ExpectedString);
}
bare_header(h)?;
self.str_body()
}
#[inline]
pub fn read_string_into(&mut self, out: &mut String) -> PResult<()> {
let s = self.read_str()?;
out.clear();
out.push_str(s);
Ok(())
}
#[inline]
pub(crate) fn str_body(&mut self) -> PResult<&'de str> {
let n = self.count()?;
self.str_text(n)
}
#[inline]
pub(crate) fn str_text(&mut self, n: usize) -> PResult<&'de str> {
let bytes = self.take(n)?;
core::str::from_utf8(bytes).map_err(|_| ErrorCode::InvalidUtf8)
}
pub fn read_bytes(&mut self) -> PResult<&'de [u8]> {
let h = self.head()?;
if header::ty(h) != header::TY_TYPED_ARRAY {
return Err(ErrorCode::ExpectedArray);
}
if !self.can_enter() {
return Err(ErrorCode::ExceededMaxDepth);
}
if header::sub(h) != header::CAT_OTHER {
byte_elements(h)?;
let n = self.count()?;
return self.take(n);
}
match header::count(h) {
header::OTHER_ALIGNED => {
let (inner, n) = self.aligned_head()?;
byte_elements(inner)?;
self.take(n)
}
header::OTHER_BOOL | header::OTHER_STRING => Err(ErrorCode::ExpectedBytes),
_ => Err(ErrorCode::InvalidHeader),
}
}
pub fn read_object<T: ReadObject<'de>>(&mut self, value: &mut T) -> PResult<()> {
let open = self.pos;
let h = self.head()?;
if header::ty(h) != header::TY_OBJECT {
return Err(ErrorCode::ExpectedObject);
}
key_width(h)?;
if header::sub(h) != header::CAT_FLOAT {
return Err(ErrorCode::UnsupportedKeyType);
}
let members = self.count()?;
self.enter()?;
self.read_object_rest(value, members, open)
}
pub fn read_object_rest<T: ReadObject<'de>>(
&mut self,
value: &mut T,
remaining: usize,
open: usize,
) -> PResult<()> {
let seen = self.rest_members::<T>(value, remaining);
self.leave();
let seen = seen?;
let mask = Fields::<O, T>::MASK;
if seen & mask != mask {
self.pos = open;
self.error_key = Fields::<O, T>::missing(seen);
return Err(ErrorCode::MissingKey);
}
Ok(())
}
#[inline(always)]
fn rest_members<T: ReadObject<'de>>(
&mut self,
value: &mut T,
remaining: usize,
) -> PResult<u64> {
let mut seen = 0u64;
for _ in 0..remaining {
self.object_member::<T>(value, &mut seen)?;
}
if let Some(run) = self.take_deferred() {
let resume = self.pos;
self.pos = run.start;
for _ in 0..run.count {
self.object_member::<T>(value, &mut seen)?;
}
self.pos = resume;
}
Ok(seen)
}
#[inline]
fn object_member<T: ReadObject<'de>>(&mut self, value: &mut T, seen: &mut u64) -> PResult<()> {
let map = T::MAP;
let keys = map.n as usize;
let n = self.count()?;
let at = self.pos;
let key = self.take(n)?;
let mut index = map.lookup_sized(T::KEYS, key);
let matched = index < keys && {
index = resolve_key::<T>(index);
T::read_field(value, index, key, self)?
};
if Fields::<O, T>::TRACK && matched {
*seen |= Fields::<O, T>::seen(index);
}
if !matched {
if O::ERROR_ON_UNKNOWN_KEYS {
self.pos = at;
return Err(ErrorCode::UnknownKey);
}
self.skip_value()?;
}
Ok(())
}
#[inline(always)]
fn take_deferred(&mut self) -> Option<Deferred> {
match self.deferred.last() {
Some(run) if run.depth == self.depth => self.deferred.pop(),
_ => None,
}
}
pub fn finish_internally_tagged(&mut self, remaining: usize) -> PResult<()> {
let result = self.unknown_members(remaining);
self.leave();
result
}
#[inline(always)]
fn unknown_members(&mut self, remaining: usize) -> PResult<()> {
for _ in 0..remaining {
self.unknown_member()?;
}
if let Some(run) = self.take_deferred() {
let resume = self.pos;
self.pos = run.start;
for _ in 0..run.count {
self.unknown_member()?;
}
self.pos = resume;
}
Ok(())
}
fn unknown_member(&mut self) -> PResult<()> {
let n = self.count()?;
let at = self.pos;
self.take(n)?;
if O::ERROR_ON_UNKNOWN_KEYS {
self.pos = at;
return Err(ErrorCode::UnknownKey);
}
self.skip_value()
}
pub fn read_enum<T: ReadEnum<'de>>(&mut self, value: &mut T) -> PResult<()> {
let open = self.pos;
let h = self.head()?;
match header::ty(h) {
header::TY_STRING => {
bare_header(h)?;
let name = self.str_body()?.as_bytes();
let index = T::MAP.lookup_sized(T::VARIANTS, name);
if index >= T::MAP.n as usize
|| !T::read_name(value, resolve_variant::<T>(index), name)?
{
self.pos = open;
return Err(ErrorCode::UnknownVariant);
}
Ok(())
}
header::TY_OBJECT => {
key_width(h)?;
if header::sub(h) != header::CAT_FLOAT {
return Err(ErrorCode::UnsupportedKeyType);
}
if self.count()? != 1 {
self.pos = open;
return Err(ErrorCode::ExpectedVariant);
}
self.nested(|r| {
let n = r.count()?;
let at = r.pos;
let name = r.take(n)?;
let index = T::MAP.lookup_sized(T::VARIANTS, name);
if index >= T::MAP.n as usize
|| !T::read_payload(value, resolve_variant::<T>(index), name, r)?
{
r.pos = at;
return Err(ErrorCode::UnknownVariant);
}
Ok(())
})
}
_ => {
self.pos = open;
Err(ErrorCode::ExpectedVariant)
}
}
}
pub fn read_internally_tagged<T: ReadInternallyTagged<'de>>(
&mut self,
value: &mut T,
) -> PResult<()> {
let open = self.pos;
let h = self.head()?;
if header::ty(h) != header::TY_OBJECT {
return Err(ErrorCode::ExpectedObject);
}
key_width(h)?;
if header::sub(h) != header::CAT_FLOAT {
return Err(ErrorCode::UnsupportedKeyType);
}
let members = self.count()?;
if members == 0 {
self.pos = open;
return Err(ErrorCode::ExpectedTag);
}
let depth = self.depth;
let runs = self.deferred.len();
let result = self.tagged_object::<T>(value, members, open);
if result.is_err() {
self.depth = depth;
self.deferred.truncate(runs);
}
result
}
#[inline(always)]
fn tagged_object<T: ReadInternallyTagged<'de>>(
&mut self,
value: &mut T,
members: usize,
open: usize,
) -> PResult<()> {
self.enter()?;
let first = self.pos;
let n = self.count()?;
let mut after = members - 1;
if self.take(n)? != T::TAG.as_bytes() {
self.pos = first;
let mut before = 0;
loop {
if before == members {
self.pos = first;
return Err(ErrorCode::ExpectedTag);
}
let n = self.count()?;
if self.take(n)? == T::TAG.as_bytes() {
break;
}
self.skip_value()?;
before += 1;
}
after = members - 1 - before;
self.deferred.push(Deferred {
start: first,
count: before,
depth: self.depth,
});
}
let at = self.pos;
let vh = self.head()?;
if header::ty(vh) != header::TY_STRING {
self.pos = first;
return Err(ErrorCode::ExpectedTag);
}
bare_header(vh)?;
let name = self.str_body()?.as_bytes();
let index = T::MAP.lookup_sized(T::VARIANTS, name);
if index >= T::MAP.n as usize
|| !T::read_variant(value, resolve_variant::<T>(index), name, self, after, open)?
{
self.pos = at;
return Err(ErrorCode::UnknownVariant);
}
Ok(())
}
pub fn read_map<F>(&mut self, entry: F) -> PResult<()>
where
F: FnMut(&mut Self, Key<'de>) -> PResult<()>,
{
self.read_map_counted(|_| entry)
}
pub fn read_map_located<F>(&mut self, entry: F) -> PResult<()>
where
F: FnMut(&mut Self, Key<'de>, usize) -> PResult<()>,
{
self.drive_map(|_| entry)
}
pub fn read_map_counted<S, F>(&mut self, start: S) -> PResult<()>
where
S: FnOnce(usize) -> F,
F: FnMut(&mut Self, Key<'de>) -> PResult<()>,
{
self.drive_map(|n| {
let mut entry = start(n);
move |r: &mut Self, key, _| entry(r, key)
})
}
fn drive_map<S, F>(&mut self, start: S) -> PResult<()>
where
S: FnOnce(usize) -> F,
F: FnMut(&mut Self, Key<'de>, usize) -> PResult<()>,
{
let h = self.head()?;
if header::ty(h) != header::TY_OBJECT {
return Err(ErrorCode::ExpectedObject);
}
let cat = header::sub(h);
let width = key_width(h)?;
let members = self.count()?;
let mut entry = start(self.honest(members));
self.nested(|r| {
for _ in 0..members {
let at = r.pos;
let (key, at) = match cat {
header::CAT_FLOAT => {
let n = r.count()?;
let at = r.pos;
(Key::Str(r.str_text(n)?), at)
}
header::CAT_SIGNED => {
(Key::Signed(sign_extend(le_u128(r.take(width)?), width)), at)
}
_ => (Key::Unsigned(le_u128(r.take(width)?)), at),
};
entry(r, key, at)?;
}
Ok(())
})
}
pub fn read_array<T: ReadArray<'de>>(&mut self, value: &mut T) -> PResult<()> {
let count = self.read_seq(|r, i| value.read_element(i, r))?;
if count != T::LEN {
return Err(ErrorCode::ArrayLengthMismatch);
}
Ok(())
}
pub fn read_seq<F>(&mut self, element: F) -> PResult<usize>
where
F: FnMut(&mut Self, usize) -> PResult<()>,
{
self.read_seq_counted(|_| element)
}
pub fn read_seq_counted<S, F>(&mut self, start: S) -> PResult<usize>
where
S: FnOnce(usize) -> F,
F: FnMut(&mut Self, usize) -> PResult<()>,
{
let installed = self.implied.is_some();
let h = self.head()?;
if !installed && h == header::COMPLEX {
return self.complex_run(start);
}
if header::ty(h) == header::TY_GENERIC_ARRAY {
bare_header(h)?;
}
self.nested(|r| r.drive(h, start))
}
fn complex_run<S, F>(&mut self, start: S) -> PResult<usize>
where
S: FnOnce(usize) -> F,
F: FnMut(&mut Self, usize) -> PResult<()>,
{
let (class, width, pairs) = self.complex_head()?;
let n = pairs.ok_or(ErrorCode::ExpectedArray)?;
if n > 0 {
decodable_elements(class)?;
}
self.have(complex_payload(width, Some(n))?)?;
let mut element = start(n);
self.run(n, header::complex_element(class), &mut element)
}
fn drive<S, F>(&mut self, h: u8, start: S) -> PResult<usize>
where
S: FnOnce(usize) -> F,
F: FnMut(&mut Self, usize) -> PResult<()>,
{
match header::ty(h) {
header::TY_GENERIC_ARRAY => {
let n = self.count()?;
let mut element = start(self.honest(n));
for i in 0..n {
element(self, i)?;
}
Ok(n)
}
header::TY_TYPED_ARRAY => self.typed(h, start),
_ => Err(ErrorCode::ExpectedArray),
}
}
fn typed<S, F>(&mut self, h: u8, start: S) -> PResult<usize>
where
S: FnOnce(usize) -> F,
F: FnMut(&mut Self, usize) -> PResult<()>,
{
match self.typed_head(h)? {
Typed::Bools(n) => {
let bytes = n.div_ceil(8);
let mut element = start(n);
let base = self.pos;
for i in 0..n {
let bit = (self.data[base + (i >> 3)] >> (i & 7)) & 1;
let h = if bit == 1 {
header::TRUE
} else {
header::FALSE
};
self.implying(h, |r| element(r, i))?;
}
self.pos = base + bytes;
Ok(n)
}
Typed::Strings(n) => {
let mut element = start(self.honest(n));
self.run(n, header::STRING, &mut element)
}
Typed::Fixed(h, n) => {
if n > 0 {
decodable_elements(h)?;
}
self.have(payload_len(h, n)?)?;
let mut element = start(n);
self.run(n, header::element_of(h), &mut element)
}
}
}
fn run<F>(&mut self, n: usize, elem: u8, element: &mut F) -> PResult<usize>
where
F: FnMut(&mut Self, usize) -> PResult<()>,
{
for i in 0..n {
self.implying(elem, |r| element(r, i))?;
}
Ok(n)
}
#[inline(always)]
fn block_head(&mut self) -> Option<(u8, usize)> {
if self.implied.is_some() {
return None;
}
let h = *self.data.get(self.pos)?;
self.pos += 1;
if h == header::COMPLEX {
let (class, _, pairs) = self.complex_head().ok()?;
return Some((header::complex_element(class), pairs?));
}
if header::ty(h) != header::TY_TYPED_ARRAY {
return None;
}
if !self.can_enter() {
return None;
}
if header::sub(h) != header::CAT_OTHER {
return Some((header::element_of(h), self.count().ok()?));
}
if header::count(h) != header::OTHER_ALIGNED {
return None;
}
let (inner, n) = self.aligned_head().ok()?;
Some((header::element_of(inner), n))
}
#[inline]
pub fn try_bulk<T: Read<'de>>(&mut self, out: &mut Vec<T>) -> PResult<bool> {
self.try_bulk_with::<crate::Same, T>(out)
}
pub fn try_bulk_with<A: ReadAs<'de, T>, T>(&mut self, out: &mut Vec<T>) -> PResult<bool> {
let start = self.pos;
if let Some((elem, n)) = self.block_head()
&& A::read_bulk(out, n, elem, self)?
{
return Ok(true);
}
self.rewind(start);
Ok(false)
}
#[inline]
pub fn read_block<T: NumericBytes>(&mut self, out: &mut Vec<T>, n: usize) -> PResult<()> {
let total = n
.checked_mul(Block::<T>::WIDTH)
.ok_or(ErrorCode::UnexpectedEnd)?;
let bytes = self.take(total)?;
out.clear();
out.reserve(n);
unsafe {
core::ptr::copy_nonoverlapping(bytes.as_ptr(), out.as_mut_ptr().cast::<u8>(), total);
out.set_len(n);
}
Ok(())
}
pub fn try_slice<T: NumericBytes>(&mut self) -> Option<&'de [T]> {
let start = self.pos;
match self.borrow_block() {
Some(block) => Some(block),
None => {
self.rewind(start);
None
}
}
}
fn borrow_block<T: NumericBytes>(&mut self) -> Option<&'de [T]> {
if cfg!(target_endian = "big") {
return None;
}
let (elem, n) = self.block_head()?;
if elem != T::ELEMENT {
return None;
}
let bytes = self.take(n.checked_mul(Block::<T>::WIDTH)?).ok()?;
let block = bytes.as_ptr().cast::<T>();
if !block.is_aligned() {
return None;
}
Some(unsafe { core::slice::from_raw_parts(block, n) })
}
pub fn skip_value(&mut self) -> PResult<()> {
self.step::<false>()
}
pub fn validate_value(&mut self) -> PResult<()> {
self.step::<true>()
}
fn step<const UTF8: bool>(&mut self) -> PResult<()> {
let installed = self.implied.is_some();
let h = self.head()?;
if installed && header::ty(h) == header::TY_UNDEFINED {
let width = header::element_width(h).ok_or(ErrorCode::InvalidHeader)?;
return self.drop_bytes(width);
}
self.skip_body::<UTF8>(h)
}
fn skip_body<const UTF8: bool>(&mut self, h: u8) -> PResult<()> {
match header::ty(h) {
header::TY_NULL_BOOL => match h {
header::NULL | header::FALSE | header::TRUE => Ok(()),
_ => Err(ErrorCode::InvalidHeader),
},
header::TY_NUMBER => {
let w =
byte_width(header::sub(h), header::count(h)).ok_or(ErrorCode::InvalidHeader)?;
self.drop_bytes(w)
}
header::TY_STRING => {
bare_header(h)?;
self.skip_str::<UTF8>()
}
header::TY_OBJECT => {
let cat = header::sub(h);
let width = key_width(h)?;
let members = self.count()?;
self.nested(|r| {
for _ in 0..members {
if cat == header::CAT_FLOAT {
r.skip_str::<UTF8>()?;
} else {
r.drop_bytes(width)?;
}
r.step::<UTF8>()?;
}
Ok(())
})
}
header::TY_GENERIC_ARRAY => {
bare_header(h)?;
let n = self.count()?;
self.nested(|r| {
for _ in 0..n {
r.step::<UTF8>()?;
}
Ok(())
})
}
header::TY_TYPED_ARRAY => self.nested(|r| r.skip_typed::<UTF8>(h)),
header::TY_EXTENSION => self.skip_extension::<UTF8>(h),
_ => Err(ErrorCode::InvalidHeader),
}
}
#[inline]
fn skip_str<const UTF8: bool>(&mut self) -> PResult<()> {
let n = self.count()?;
let bytes = self.take(n)?;
if UTF8 && core::str::from_utf8(bytes).is_err() {
return Err(ErrorCode::InvalidUtf8);
}
Ok(())
}
fn skip_typed<const UTF8: bool>(&mut self, h: u8) -> PResult<()> {
match self.typed_head(h)? {
Typed::Bools(n) => self.drop_bytes(n.div_ceil(8)),
Typed::Strings(n) => {
for _ in 0..n {
self.skip_str::<UTF8>()?;
}
Ok(())
}
Typed::Fixed(h, n) => {
let total = payload_len(h, n)?;
self.drop_bytes(total)
}
}
}
fn skip_extension<const UTF8: bool>(&mut self, h: u8) -> PResult<()> {
match header::ext_id(h) {
header::EXT_DELIMITER => Err(ErrorCode::InvalidHeader),
header::EXT_TYPE_TAG => {
self.size()?;
self.nested(|r| r.step::<UTF8>())
}
header::EXT_MATRIX => {
self.drop_bytes(1)?;
self.nested(|r| {
r.step::<UTF8>()?;
r.step::<UTF8>()
})
}
header::EXT_COMPLEX => {
let (_, width, pairs) = self.complex_head()?;
self.drop_bytes(complex_payload(width, pairs)?)
}
_ => Err(ErrorCode::UnsupportedFeature),
}
}
pub fn seek(&mut self, pointer: &str) -> PResult<()> {
let levels = self.walk(pointer)?;
self.depth -= levels;
Ok(())
}
pub(crate) fn read_at<T: Read<'de>>(&mut self, pointer: &str, value: &mut T) -> PResult<()> {
let levels = self.walk(pointer)?;
let result = value.read(self);
self.depth -= levels;
result
}
fn walk(&mut self, pointer: &str) -> PResult<u32> {
let depth = self.depth;
match self.descend_path(pointer) {
Ok(()) => Ok(self.depth - depth),
Err(code) => {
self.depth = depth;
Err(code)
}
}
}
fn descend_path(&mut self, pointer: &str) -> PResult<()> {
if pointer.is_empty() {
return Ok(());
}
let rest = pointer.strip_prefix('/').ok_or(ErrorCode::InvalidPointer)?;
for token in rest.split('/') {
check_escapes(token)?;
self.descend(token)?;
}
Ok(())
}
fn descend(&mut self, token: &str) -> PResult<()> {
let h = self.head()?;
match header::ty(h) {
header::TY_OBJECT => self.descend_object(h, token),
header::TY_GENERIC_ARRAY => {
bare_header(h)?;
let i = index(token)?;
let n = self.count()?;
self.enter()?;
if i >= n {
return Err(ErrorCode::NoSuchValue);
}
for _ in 0..i {
self.skip_value()?;
}
Ok(())
}
header::TY_TYPED_ARRAY => self.descend_typed(h, index(token)?),
header::TY_EXTENSION if h == header::DELIMITER => Err(ErrorCode::InvalidHeader),
header::TY_NULL_BOOL | header::TY_NUMBER | header::TY_STRING | header::TY_EXTENSION => {
Err(ErrorCode::NoSuchValue)
}
_ => Err(ErrorCode::InvalidHeader),
}
}
fn descend_object(&mut self, h: u8, token: &str) -> PResult<()> {
let width = key_width(h)?;
let wanted = match header::sub(h) {
header::CAT_FLOAT => Key::Str(token),
header::CAT_SIGNED => Key::Signed(parse_int_text(token).ok_or(ErrorCode::NoSuchValue)?),
_ => Key::Unsigned(parse_int_text(token).ok_or(ErrorCode::NoSuchValue)?),
};
let members = self.count()?;
self.enter()?;
for _ in 0..members {
let hit = match wanted {
Key::Str(t) => {
let n = self.count()?;
token_eq(t, self.take(n)?)
}
Key::Signed(v) => sign_extend(le_u128(self.take(width)?), width) == v,
Key::Unsigned(v) => le_u128(self.take(width)?) == v,
};
if hit {
return Ok(());
}
self.skip_value()?;
}
Err(ErrorCode::NoSuchValue)
}
fn descend_typed(&mut self, h: u8, i: usize) -> PResult<()> {
self.enter()?;
let form = self.typed_head(h)?;
let (Typed::Bools(n) | Typed::Strings(n) | Typed::Fixed(_, n)) = form;
if i >= n {
return Err(ErrorCode::NoSuchValue);
}
match form {
Typed::Bools(_) => {
let byte = self.data[self.pos + (i >> 3)];
self.install(if (byte >> (i & 7)) & 1 == 1 {
header::TRUE
} else {
header::FALSE
});
Ok(())
}
Typed::Strings(_) => {
for _ in 0..i {
self.skip_str::<false>()?;
}
self.install(header::STRING);
Ok(())
}
Typed::Fixed(h, _) => {
let width =
byte_width(header::sub(h), header::count(h)).ok_or(ErrorCode::InvalidHeader)?;
self.drop_bytes(i.checked_mul(width).ok_or(ErrorCode::UnexpectedEnd)?)?;
self.have(width)?;
self.install(header::element_of(h));
Ok(())
}
}
}
}
fn check_escapes(token: &str) -> PResult<()> {
let t = token.as_bytes();
let mut i = 0;
while i < t.len() {
if t[i] == b'~' {
match t.get(i + 1) {
Some(b'0' | b'1') => i += 1,
_ => return Err(ErrorCode::InvalidPointer),
}
}
i += 1;
}
Ok(())
}
fn token_eq(token: &str, key: &[u8]) -> bool {
let t = token.as_bytes();
let mut i = 0;
let mut j = 0;
while i < t.len() {
let (want, step) = match (t[i], t.get(i + 1)) {
(b'~', Some(b'0')) => (b'~', 2),
(b'~', Some(b'1')) => (b'/', 2),
(b, _) => (b, 1),
};
if key.get(j) != Some(&want) {
return false;
}
i += step;
j += 1;
}
j == key.len()
}
fn index(token: &str) -> PResult<usize> {
if token == "-" {
return Err(ErrorCode::NoSuchValue);
}
let t = token.as_bytes();
let shaped =
!t.is_empty() && t.iter().all(u8::is_ascii_digit) && !(t[0] == b'0' && t.len() > 1);
if !shaped {
return Err(ErrorCode::InvalidPointer);
}
token.parse().map_err(|_| ErrorCode::NoSuchValue)
}
pub(crate) fn key_width(h: u8) -> PResult<usize> {
let cat = header::sub(h);
match cat {
header::CAT_FLOAT if header::count(h) == 0 => Ok(0),
header::CAT_SIGNED | header::CAT_UNSIGNED => {
byte_width(cat, header::count(h)).ok_or(ErrorCode::InvalidHeader)
}
_ => Err(ErrorCode::InvalidHeader),
}
}
pub(crate) fn bare_header(h: u8) -> PResult<()> {
if header::sub(h) == 0 && header::count(h) == 0 {
Ok(())
} else {
Err(ErrorCode::InvalidHeader)
}
}
pub(crate) fn fixed_width(h: u8) -> PResult<usize> {
byte_width(header::sub(h), header::count(h)).ok_or(ErrorCode::InvalidHeader)
}
fn decodable_elements(h: u8) -> PResult<()> {
header::decodable_width(header::sub(h), header::count(h)).map(drop)
}
#[inline]
pub(crate) fn bool_padding(n: usize, last: u8) -> PResult<()> {
let used = n & 7;
if used != 0 && last >> used != 0 {
return Err(ErrorCode::InvalidPadding);
}
Ok(())
}
#[inline]
pub(crate) fn aligned_padding(pad: u8, width: usize) -> PResult<()> {
if usize::from(pad) >= width {
return Err(ErrorCode::InvalidPadding);
}
Ok(())
}
pub(crate) fn payload_len(h: u8, n: usize) -> PResult<usize> {
n.checked_mul(fixed_width(h)?)
.ok_or(ErrorCode::UnexpectedEnd)
}
pub(crate) fn complex_payload(width: usize, pairs: Option<usize>) -> PResult<usize> {
pairs
.unwrap_or(1)
.checked_mul(2 * width)
.ok_or(ErrorCode::UnexpectedEnd)
}
fn byte_elements(h: u8) -> PResult<()> {
fixed_width(h)?;
match header::sub(h) {
header::CAT_SIGNED | header::CAT_UNSIGNED if header::count(h) == 0 => Ok(()),
_ => Err(ErrorCode::ExpectedBytes),
}
}
#[inline]
fn widen(cat: u8, code: u8, bytes: &[u8]) -> PResult<f64> {
match cat {
header::CAT_FLOAT => match code {
0 => Ok(bf16_to_f32(u16::from_le_bytes([bytes[0], bytes[1]])) as f64),
1 => Ok(f16_to_f32(u16::from_le_bytes([bytes[0], bytes[1]])) as f64),
2 => Ok(f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as f64),
3 => Ok(f64::from_le_bytes(bytes.try_into().expect("8 bytes"))),
_ => Err(ErrorCode::UnsupportedFeature),
},
header::CAT_UNSIGNED => Ok(le_u128(bytes) as f64),
header::CAT_SIGNED => Ok(sign_extend(le_u128(bytes), bytes.len()) as f64),
_ => Err(ErrorCode::ExpectedNumber),
}
}
pub(crate) fn le_u128(bytes: &[u8]) -> u128 {
let mut v: u128 = 0;
for (i, &b) in bytes.iter().enumerate() {
v |= (b as u128) << (8 * i);
}
v
}
#[inline]
pub(crate) fn sign_extend(v: u128, width: usize) -> i128 {
let bits = 8 * width;
if bits >= 128 {
return v as i128;
}
let shift = 128 - bits;
((v << shift) as i128) >> shift
}
#[inline]
pub(crate) fn bf16_to_f32(bits: u16) -> f32 {
f32::from_bits((bits as u32) << 16)
}
pub(crate) fn f16_to_f32(bits: u16) -> f32 {
let sign = ((bits >> 15) as u32) << 31;
let exp = ((bits >> 10) & 0x1f) as u32;
let man = (bits & 0x3ff) as u32;
let rest = match exp {
0 if man == 0 => 0,
0 => {
let k = 31 - man.leading_zeros();
let e = k + 127 - 24;
(e << 23) | ((man << (23 - k)) & 0x007f_ffff)
}
0x1f => 0x7f80_0000 | (man << 13),
_ => ((exp + 127 - 15) << 23) | (man << 13),
};
f32::from_bits(sign | rest)
}