use crate::error::{Error, Result};
use crate::header::*;
use crate::size::read_size;
use serde::Deserialize;
use simdutf8::basic::from_utf8;
pub fn from_field<'de, T: Deserialize<'de>>(bytes: &'de [u8], pointer: &str) -> Result<T> {
let tokens = parse_json_pointer(pointer)?;
let mut pos: usize = 0;
navigate_to(bytes, &mut pos, &tokens)?;
let mut de = crate::de::Deserializer::from_slice_at(bytes, pos);
let value = T::deserialize(&mut de)?;
Ok(value)
}
pub fn from_field_slice<T: serde::de::DeserializeOwned>(
bytes: &[u8],
pointer: &str,
start: usize,
count: usize,
) -> Result<T> {
let tokens = parse_json_pointer(pointer)?;
let mut pos: usize = 0;
navigate_to(bytes, &mut pos, &tokens)?;
let header = read_byte(bytes, &mut pos)?;
let ty = parse_type(header);
if ty != TYPE_TYPED_ARRAY {
return Err(Error::InvalidType(
"from_field_slice: target is not a typed array",
));
}
let cat = parse_subtype(header);
if cat == ARRAY_BOOL_OR_STRING {
return Err(Error::Unsupported(
"slicing not supported for boolean or string typed arrays",
));
}
let bc = parse_byte_count_code(header);
let elem_size = byte_count_to_bytes(bc)?;
let len = read_size(bytes, &mut pos)? as usize;
let end = start.checked_add(count).ok_or(Error::InvalidSize)?;
if end > len {
return Err(Error::msg(format!(
"slice [{start}..{end}) out of bounds (array length {len})"
)));
}
let skip_bytes = elem_size.checked_mul(start).ok_or(Error::InvalidSize)?;
pos = pos.checked_add(skip_bytes).ok_or(Error::InvalidSize)?;
let slice_data_len = elem_size.checked_mul(count).ok_or(Error::InvalidSize)?;
if pos + slice_data_len > bytes.len() {
return Err(Error::Eof);
}
let mut buf = Vec::with_capacity(1 + 8 + slice_data_len);
buf.push(header);
crate::size::write_size(count as u64, &mut buf);
buf.extend_from_slice(&bytes[pos..pos + slice_data_len]);
let mut de = crate::de::Deserializer::from_slice_at(&buf, 0);
let value = T::deserialize(&mut de)?;
Ok(value)
}
fn parse_json_pointer(pointer: &str) -> Result<Vec<String>> {
if pointer.is_empty() {
return Ok(Vec::new());
}
if !pointer.starts_with('/') {
return Err(Error::msg(format!(
"invalid JSON Pointer: must be empty or start with '/' (got '{pointer}')"
)));
}
let parts: Vec<String> = pointer[1..]
.split('/')
.map(|p| {
p.replace("~1", "/").replace("~0", "~")
})
.collect();
Ok(parts)
}
fn navigate_to(input: &[u8], pos: &mut usize, tokens: &[String]) -> Result<()> {
for token in tokens {
let header = read_byte(input, pos)?;
let ty = parse_type(header);
match ty {
TYPE_GENERIC_ARRAY => {
let len = read_size(input, pos)? as usize;
let idx: usize = token.parse().map_err(|_| {
Error::msg(format!(
"array index '{token}' is not a valid non-negative integer"
))
})?;
if idx >= len {
return Err(Error::msg(format!(
"array index {idx} out of bounds (length {len})"
)));
}
for _ in 0..idx {
skip_value(input, pos)?;
}
}
TYPE_OBJECT => {
let key_type = parse_subtype(header);
let bc = parse_byte_count_code(header);
let count = read_size(input, pos)? as usize;
let found = match key_type {
KEY_STRING => find_string_key(input, pos, count, token)?,
KEY_SIGNED => {
let target: i64 = token.parse().map_err(|_| {
Error::msg(format!(
"object has integer keys but pointer token '{token}' is not an integer"
))
})?;
find_signed_key(input, pos, count, bc, target)?
}
KEY_UNSIGNED => {
let target: u64 = token.parse().map_err(|_| {
Error::msg(format!(
"object has integer keys but pointer token '{token}' is not an integer"
))
})?;
find_unsigned_key(input, pos, count, bc, target)?
}
_ => return Err(Error::InvalidHeader(header)),
};
if !found {
return Err(Error::msg(format!("key '{token}' not found in object")));
}
}
_ => {
return Err(Error::msg(format!(
"cannot navigate into type {ty} at pointer segment '{token}'"
)));
}
}
}
Ok(())
}
fn find_string_key(input: &[u8], pos: &mut usize, count: usize, target: &str) -> Result<bool> {
for _ in 0..count {
let key_len = read_size(input, pos)? as usize;
if *pos + key_len > input.len() {
return Err(Error::Eof);
}
let key_bytes = &input[*pos..*pos + key_len];
*pos += key_len;
let key = from_utf8(key_bytes).map_err(|_| Error::InvalidType("invalid utf-8 in key"))?;
if key == target {
return Ok(true);
}
skip_value(input, pos)?;
}
Ok(false)
}
fn find_signed_key(
input: &[u8],
pos: &mut usize,
count: usize,
byte_code: u8,
target: i64,
) -> Result<bool> {
let nbytes = byte_count_to_bytes(byte_code)?;
for _ in 0..count {
let key_val = read_signed_int(input, pos, nbytes)?;
if key_val == target as i128 {
return Ok(true);
}
skip_value(input, pos)?;
}
Ok(false)
}
fn find_unsigned_key(
input: &[u8],
pos: &mut usize,
count: usize,
byte_code: u8,
target: u64,
) -> Result<bool> {
let nbytes = byte_count_to_bytes(byte_code)?;
for _ in 0..count {
let key_val = read_unsigned_int(input, pos, nbytes)?;
if key_val == target as u128 {
return Ok(true);
}
skip_value(input, pos)?;
}
Ok(false)
}
pub fn skip_value(input: &[u8], pos: &mut usize) -> Result<()> {
let header = read_byte(input, pos)?;
let ty = parse_type(header);
match ty {
TYPE_NULL_BOOL => {
}
TYPE_NUMBER => {
let bc = parse_byte_count_code(header);
let nbytes = byte_count_to_bytes(bc)?;
advance(input, pos, nbytes)?;
}
TYPE_STRING => {
let len = read_size(input, pos)? as usize;
advance(input, pos, len)?;
}
TYPE_OBJECT => {
let key_type = parse_subtype(header);
let bc = parse_byte_count_code(header);
let count = read_size(input, pos)? as usize;
match key_type {
KEY_STRING => {
for _ in 0..count {
let key_len = read_size(input, pos)? as usize;
advance(input, pos, key_len)?; skip_value(input, pos)?; }
}
KEY_SIGNED | KEY_UNSIGNED => {
let key_size = byte_count_to_bytes(bc)?;
for _ in 0..count {
advance(input, pos, key_size)?; skip_value(input, pos)?; }
}
_ => return Err(Error::InvalidHeader(header)),
}
}
TYPE_TYPED_ARRAY => {
let cat = parse_subtype(header);
let bc = parse_byte_count_code(header);
let len = read_size(input, pos)? as usize;
if cat == ARRAY_BOOL_OR_STRING {
let is_string = (header & 0b0010_0000) != 0;
if is_string {
for _ in 0..len {
let s = read_size(input, pos)? as usize;
advance(input, pos, s)?;
}
} else {
let packed = len.div_ceil(8);
advance(input, pos, packed)?;
}
} else {
let elem_size = byte_count_to_bytes(bc)?;
let total = elem_size.checked_mul(len).ok_or(Error::InvalidSize)?;
advance(input, pos, total)?;
}
}
TYPE_GENERIC_ARRAY => {
let len = read_size(input, pos)? as usize;
for _ in 0..len {
skip_value(input, pos)?;
}
}
TYPE_EXTENSION => {
let ext = parse_extension_id(header);
match ext {
EXT_TYPE_TAG => {
skip_value(input, pos)?; skip_value(input, pos)?; }
EXT_DELIMITER => { }
EXT_MATRICES => {
advance(input, pos, 1)?; skip_value(input, pos)?; skip_value(input, pos)?; }
EXT_COMPLEX => {
let ch = read_byte(input, pos)?;
let class = (ch >> 3) & 0x03;
if class > 2 {
return Err(Error::InvalidHeader(ch));
}
let is_array = (ch & 0x01) != 0;
let cbc = (ch >> 5) & 0x07;
let component_bytes = complex_component_bytes(class, cbc)
.ok_or(Error::Unsupported("unsupported complex width"))?;
let n = if is_array {
read_size(input, pos)? as usize
} else {
1
};
let total = (2usize)
.checked_mul(n)
.and_then(|v| v.checked_mul(component_bytes))
.ok_or(Error::InvalidSize)?;
advance(input, pos, total)?;
}
_ => {
return Err(Error::Unsupported("cannot skip unsupported extension"));
}
}
}
_ => return Err(Error::InvalidHeader(header)),
}
Ok(())
}
#[inline]
fn byte_count_to_bytes(code: u8) -> Result<usize> {
match code {
0 => Ok(1),
1 => Ok(2),
2 => Ok(4),
3 => Ok(8),
4 => Ok(16),
_ => Err(Error::Unsupported("byte width > 16 not supported")),
}
}
#[inline]
fn read_byte(input: &[u8], pos: &mut usize) -> Result<u8> {
if *pos >= input.len() {
return Err(Error::Eof);
}
let b = input[*pos];
*pos += 1;
Ok(b)
}
#[inline]
fn advance(input: &[u8], pos: &mut usize, n: usize) -> Result<()> {
let end = pos.checked_add(n).ok_or(Error::InvalidSize)?;
if end > input.len() {
return Err(Error::Eof);
}
*pos = end;
Ok(())
}
fn read_signed_int(input: &[u8], pos: &mut usize, nbytes: usize) -> Result<i128> {
if *pos + nbytes > input.len() {
return Err(Error::Eof);
}
let s = &input[*pos..*pos + nbytes];
*pos += nbytes;
let mut buf = [0u8; 16];
buf[..nbytes].copy_from_slice(s);
if nbytes < 16 && (s[nbytes - 1] & 0x80) != 0 {
for b in &mut buf[nbytes..] {
*b = 0xFF;
}
}
Ok(i128::from_le_bytes(buf))
}
fn read_unsigned_int(input: &[u8], pos: &mut usize, nbytes: usize) -> Result<u128> {
if *pos + nbytes > input.len() {
return Err(Error::Eof);
}
let s = &input[*pos..*pos + nbytes];
*pos += nbytes;
let mut buf = [0u8; 16];
buf[..nbytes].copy_from_slice(s);
Ok(u128::from_le_bytes(buf))
}