use crate::error::{Error, Result};
use crate::header::*;
use crate::size::{encode_size_to_array, read_size, write_size};
use half::{bf16, f16};
use std::char;
use std::str;
const MAX_RECURSION_DEPTH: usize = 256;
pub fn json_slice_to_beve(json: &[u8]) -> Result<Vec<u8>> {
let mut parser = JsonParser::new(json);
parser.skip_ws();
let mut builder = BeveBuilder::new();
parser.parse_value(&mut builder, 0)?;
parser.skip_ws();
if !parser.is_eof() {
return Err(Error::InvalidType("unexpected trailing JSON data"));
}
Ok(builder.into_vec())
}
pub fn json_str_to_beve(json: &str) -> Result<Vec<u8>> {
json_slice_to_beve(json.as_bytes())
}
pub fn beve_slice_to_json(beve_bytes: &[u8]) -> Result<Vec<u8>> {
let mut reader = BeveReader::new(beve_bytes);
let mut out = Vec::new();
while !reader.is_finished() {
write_value(&mut reader, &mut out, 0)?;
}
Ok(out)
}
pub fn beve_slice_to_json_string(beve_bytes: &[u8]) -> Result<String> {
let bytes = beve_slice_to_json(beve_bytes)?;
String::from_utf8(bytes).map_err(|_| Error::InvalidType("json output is not valid utf-8"))
}
struct BeveReader<'a> {
buf: &'a [u8],
pos: usize,
}
impl<'a> BeveReader<'a> {
fn new(buf: &'a [u8]) -> Self {
Self { buf, pos: 0 }
}
fn is_finished(&self) -> bool {
self.pos >= self.buf.len()
}
fn remaining(&self) -> usize {
self.buf.len().saturating_sub(self.pos)
}
fn read_byte(&mut self) -> Result<u8> {
if self.pos >= self.buf.len() {
return Err(Error::Eof);
}
let b = self.buf[self.pos];
self.pos += 1;
Ok(b)
}
fn read_exact(&mut self, len: usize) -> Result<&'a [u8]> {
if self.remaining() < len {
return Err(Error::Eof);
}
let start = self.pos;
self.pos += len;
Ok(&self.buf[start..start + len])
}
fn read_size(&mut self) -> Result<u64> {
let mut idx = self.pos;
let n = read_size(self.buf, &mut idx)?;
self.pos = idx;
Ok(n)
}
}
struct BeveBuilder {
buf: Vec<u8>,
}
impl BeveBuilder {
fn new() -> Self {
Self { buf: Vec::new() }
}
fn into_vec(self) -> Vec<u8> {
self.buf
}
fn push(&mut self, b: u8) {
self.buf.push(b);
}
fn extend(&mut self, bytes: &[u8]) {
self.buf.extend_from_slice(bytes);
}
fn write_null(&mut self) {
self.push(0);
}
fn write_bool(&mut self, value: bool) {
self.push(if value { 0x18 } else { 0x08 });
}
fn write_string(&mut self, value: &str) {
self.push(TYPE_STRING);
write_size(value.len() as u64, &mut self.buf);
self.extend(value.as_bytes());
}
fn write_unsigned(&mut self, value: u128) {
let (code, bytes) = match value {
v if v <= u8::MAX as u128 => (0, 1),
v if v <= u16::MAX as u128 => (1, 2),
v if v <= u32::MAX as u128 => (2, 4),
v if v <= u64::MAX as u128 => (3, 8),
_ => (4, 16),
};
self.push(make_header(TYPE_NUMBER, NUM_UNSIGNED, code));
let le = value.to_le_bytes();
self.extend(&le[..bytes]);
}
fn write_signed(&mut self, value: i128) {
let (code, bytes) = if value >= i8::MIN as i128 && value <= i8::MAX as i128 {
(0, 1)
} else if value >= i16::MIN as i128 && value <= i16::MAX as i128 {
(1, 2)
} else if value >= i32::MIN as i128 && value <= i32::MAX as i128 {
(2, 4)
} else if value >= i64::MIN as i128 && value <= i64::MAX as i128 {
(3, 8)
} else {
(4, 16)
};
self.push(make_header(TYPE_NUMBER, NUM_SIGNED, code));
let le = value.to_le_bytes();
self.extend(&le[..bytes]);
}
fn write_float64(&mut self, value: f64) -> Result<()> {
if !value.is_finite() {
return Err(Error::Unsupported(
"non-finite float not representable in JSON",
));
}
self.push(make_header(TYPE_NUMBER, NUM_FLOAT, 3));
self.extend(&value.to_le_bytes());
Ok(())
}
fn reserve_patch(&mut self) -> Patch {
let pos = self.buf.len();
self.buf.extend_from_slice(&[0u8; 8]);
Patch { pos }
}
fn finalize_patch(&mut self, patch: Patch, count: usize) {
let payload_start = patch.pos + 8;
let payload_end = self.buf.len();
let mut tmp = [0u8; 8];
let used = encode_size_to_array(count as u64, &mut tmp);
self.buf[patch.pos..patch.pos + used].copy_from_slice(&tmp[..used]);
let delta = 8 - used;
if delta > 0 {
if payload_start < payload_end {
self.buf
.copy_within(payload_start..payload_end, patch.pos + used);
}
self.buf.truncate(payload_end - delta);
}
}
fn begin_array(&mut self) -> Patch {
self.push(TYPE_GENERIC_ARRAY);
self.reserve_patch()
}
fn begin_object(&mut self) -> Patch {
self.push(TYPE_OBJECT | (KEY_STRING << 3));
self.reserve_patch()
}
}
#[derive(Clone, Copy)]
struct Patch {
pos: usize,
}
struct JsonParser<'a> {
src: &'a [u8],
pos: usize,
}
impl<'a> JsonParser<'a> {
fn new(src: &'a [u8]) -> Self {
Self { src, pos: 0 }
}
fn is_eof(&self) -> bool {
self.pos >= self.src.len()
}
fn skip_ws(&mut self) {
while self.pos < self.src.len() {
match self.src[self.pos] {
b' ' | b'\t' | b'\n' | b'\r' => self.pos += 1,
_ => break,
}
}
}
fn peek(&self) -> Option<u8> {
self.src.get(self.pos).copied()
}
fn advance(&mut self) -> Option<u8> {
if self.pos >= self.src.len() {
None
} else {
let b = self.src[self.pos];
self.pos += 1;
Some(b)
}
}
fn expect_byte(&mut self, expected: u8) -> Result<()> {
match self.advance() {
Some(b) if b == expected => Ok(()),
_ => Err(Error::InvalidType("unexpected JSON character")),
}
}
fn parse_value(&mut self, builder: &mut BeveBuilder, depth: usize) -> Result<()> {
if depth >= MAX_RECURSION_DEPTH {
return Err(Error::Unsupported("json recursion depth exceeded"));
}
self.skip_ws();
let ch = self.peek().ok_or(Error::Eof)?;
match ch {
b'n' => {
self.expect_literal(b"null")?;
builder.write_null();
}
b't' => {
self.expect_literal(b"true")?;
builder.write_bool(true);
}
b'f' => {
self.expect_literal(b"false")?;
builder.write_bool(false);
}
b'"' => {
let s = self.parse_string()?;
builder.write_string(&s);
}
b'[' => {
self.advance();
self.skip_ws();
let patch = builder.begin_array();
let mut count = 0usize;
if self.consume_if(b']') {
builder.finalize_patch(patch, count);
return Ok(());
}
loop {
self.parse_value(builder, depth + 1)?;
count += 1;
self.skip_ws();
if self.consume_if(b',') {
self.skip_ws();
continue;
}
self.expect_byte(b']')?;
break;
}
builder.finalize_patch(patch, count);
}
b'{' => {
self.advance();
self.skip_ws();
let patch = builder.begin_object();
let mut count = 0usize;
if self.consume_if(b'}') {
builder.finalize_patch(patch, count);
return Ok(());
}
loop {
self.skip_ws();
if self.peek() != Some(b'"') {
return Err(Error::InvalidType("json object keys must be strings"));
}
let key = self.parse_string()?;
write_size(key.len() as u64, &mut builder.buf);
builder.extend(key.as_bytes());
self.skip_ws();
self.expect_byte(b':')?;
self.skip_ws();
self.parse_value(builder, depth + 1)?;
count += 1;
self.skip_ws();
if self.consume_if(b',') {
self.skip_ws();
continue;
}
self.expect_byte(b'}')?;
break;
}
builder.finalize_patch(patch, count);
}
b'-' | b'0'..=b'9' => {
let number = self.parse_number()?;
match number {
ParsedNumber::Unsigned(v) => builder.write_unsigned(v),
ParsedNumber::Signed(v) => builder.write_signed(v),
ParsedNumber::Float(v) => builder.write_float64(v)?,
}
}
_ => return Err(Error::InvalidType("unexpected JSON token")),
}
Ok(())
}
fn consume_if(&mut self, expected: u8) -> bool {
if self.peek() == Some(expected) {
self.pos += 1;
true
} else {
false
}
}
fn expect_literal(&mut self, literal: &[u8]) -> Result<()> {
for &b in literal {
if self.advance() != Some(b) {
return Err(Error::InvalidType("unexpected JSON literal"));
}
}
Ok(())
}
fn parse_string(&mut self) -> Result<String> {
if self.advance() != Some(b'"') {
return Err(Error::InvalidType("expected string"));
}
let mut result = String::new();
let mut start = self.pos;
while let Some(b) = self.advance() {
if b == b'"' {
result.push_str(
str::from_utf8(&self.src[start..self.pos - 1])
.map_err(|_| Error::InvalidType("invalid utf-8 in JSON string"))?,
);
return Ok(result);
} else if b == b'\\' {
result.push_str(
str::from_utf8(&self.src[start..self.pos - 1])
.map_err(|_| Error::InvalidType("invalid utf-8 in JSON string"))?,
);
let escaped = self
.advance()
.ok_or(Error::InvalidType("unterminated escape in JSON string"))?;
match escaped {
b'"' => result.push('"'),
b'\\' => result.push('\\'),
b'/' => result.push('/'),
b'b' => result.push('\u{0008}'),
b'f' => result.push('\u{000C}'),
b'n' => result.push('\n'),
b'r' => result.push('\r'),
b't' => result.push('\t'),
b'u' => {
let code = self.parse_hex_quad()?;
if (0xD800..=0xDBFF).contains(&code) {
if self.advance() != Some(b'\\') || self.advance() != Some(b'u') {
return Err(Error::InvalidType("invalid unicode surrogate pair"));
}
let low = self.parse_hex_quad()?;
if !(0xDC00..=0xDFFF).contains(&low) {
return Err(Error::InvalidType("invalid unicode surrogate pair"));
}
let composed =
0x10000 + (((code - 0xD800) as u32) << 10) + (low - 0xDC00) as u32;
if let Some(ch) = char::from_u32(composed) {
result.push(ch);
} else {
return Err(Error::InvalidType("invalid unicode codepoint"));
}
} else if let Some(ch) = char::from_u32(code as u32) {
result.push(ch);
} else {
return Err(Error::InvalidType("invalid unicode codepoint"));
}
}
_ => return Err(Error::InvalidType("invalid escape in JSON string")),
}
start = self.pos;
} else if b < 0x20 {
return Err(Error::InvalidType("control character in JSON string"));
}
}
Err(Error::InvalidType("unterminated JSON string"))
}
fn parse_hex_quad(&mut self) -> Result<u16> {
let mut value: u16 = 0;
for _ in 0..4 {
let b = self
.advance()
.ok_or(Error::InvalidType("unexpected end in \\u escape"))?;
let digit = match b {
b'0'..=b'9' => (b - b'0') as u16,
b'a'..=b'f' => (10 + b - b'a') as u16,
b'A'..=b'F' => (10 + b - b'A') as u16,
_ => return Err(Error::InvalidType("invalid hex digit in \\u escape")),
};
value = (value << 4) | digit;
}
Ok(value)
}
fn parse_number(&mut self) -> Result<ParsedNumber> {
let start = self.pos;
let mut is_float = false;
if self.peek() == Some(b'-') {
self.pos += 1;
}
match self.advance() {
Some(b'0') => {}
Some(b'1'..=b'9') => {
while matches!(self.peek(), Some(b'0'..=b'9')) {
self.pos += 1;
}
}
_ => return Err(Error::InvalidType("invalid number")),
}
if let Some(b'.') = self.peek() {
is_float = true;
self.pos += 1;
if !matches!(self.peek(), Some(b'0'..=b'9')) {
return Err(Error::InvalidType("invalid number"));
}
while matches!(self.peek(), Some(b'0'..=b'9')) {
self.pos += 1;
}
}
if matches!(self.peek(), Some(b'e') | Some(b'E')) {
is_float = true;
self.pos += 1;
if matches!(self.peek(), Some(b'+') | Some(b'-')) {
self.pos += 1;
}
if !matches!(self.peek(), Some(b'0'..=b'9')) {
return Err(Error::InvalidType("invalid number exponent"));
}
while matches!(self.peek(), Some(b'0'..=b'9')) {
self.pos += 1;
}
}
let slice = &self.src[start..self.pos];
if !is_float {
let negative = slice[0] == b'-';
let digits = if negative { &slice[1..] } else { slice };
if digits.len() > 1 && digits[0] == b'0' {
return Err(Error::InvalidType("leading zeros not allowed"));
}
if negative {
let s = str::from_utf8(slice).map_err(|_| Error::InvalidType("invalid number"))?;
let value = s.parse::<i128>().map_err(|_| {
Error::Unsupported("integer outside representable range for BEVE")
})?;
Ok(ParsedNumber::Signed(value))
} else {
let s = str::from_utf8(slice).map_err(|_| Error::InvalidType("invalid number"))?;
let value = s.parse::<u128>().map_err(|_| {
Error::Unsupported("integer outside representable range for BEVE")
})?;
Ok(ParsedNumber::Unsigned(value))
}
} else {
let s = str::from_utf8(slice).map_err(|_| Error::InvalidType("invalid number"))?;
let value = s
.parse::<f64>()
.map_err(|_| Error::InvalidType("invalid floating point literal"))?;
if !value.is_finite() {
return Err(Error::Unsupported(
"non-finite float not representable in JSON",
));
}
Ok(ParsedNumber::Float(value))
}
}
}
enum ParsedNumber {
Unsigned(u128),
Signed(i128),
Float(f64),
}
fn write_value(reader: &mut BeveReader<'_>, out: &mut Vec<u8>, depth: usize) -> Result<()> {
if depth >= MAX_RECURSION_DEPTH {
return Err(Error::Unsupported("beve recursion depth exceeded"));
}
let header = reader.read_byte()?;
let ty = parse_type(header);
match ty {
TYPE_NULL_BOOL => {
if header == 0 {
out.extend_from_slice(b"null");
} else if is_bool(header) {
if bool_value(header)? {
out.extend_from_slice(b"true");
} else {
out.extend_from_slice(b"false");
}
} else {
return Err(Error::InvalidHeader(header));
}
}
TYPE_NUMBER => {
write_number(reader, out, header)?;
}
TYPE_STRING => {
let len = reader.read_size()? as usize;
let bytes = reader.read_exact(len)?;
let s = str::from_utf8(bytes)
.map_err(|_| Error::InvalidType("invalid utf-8 in beve string"))?;
write_json_string(out, s);
}
TYPE_OBJECT => {
write_object(reader, out, header, depth)?;
}
TYPE_GENERIC_ARRAY => {
let len = reader.read_size()? as usize;
out.push(b'[');
for i in 0..len {
if i > 0 {
out.push(b',');
}
write_value(reader, out, depth + 1)?;
}
out.push(b']');
}
TYPE_TYPED_ARRAY => {
write_typed_array(reader, out, header)?;
}
TYPE_EXTENSION => {
write_extension(reader, out, header, depth)?;
}
_ => return Err(Error::InvalidHeader(header)),
}
Ok(())
}
fn write_number(reader: &mut BeveReader<'_>, out: &mut Vec<u8>, header: u8) -> Result<()> {
let subtype = parse_subtype(header);
let byte_code = parse_byte_count_code(header);
match subtype {
NUM_FLOAT => match byte_code {
0 => {
let raw = reader.read_exact(2)?;
let bits = u16::from_le_bytes([raw[0], raw[1]]);
let value = bf16::from_bits(bits).to_f32() as f64;
out.extend_from_slice(value.to_string().as_bytes());
}
1 => {
let raw = reader.read_exact(2)?;
let bits = u16::from_le_bytes([raw[0], raw[1]]);
let value = f16::from_bits(bits).to_f32() as f64;
out.extend_from_slice(value.to_string().as_bytes());
}
2 => {
let raw = reader.read_exact(4)?;
let mut arr = [0u8; 4];
arr.copy_from_slice(raw);
let value = f32::from_le_bytes(arr) as f64;
out.extend_from_slice(value.to_string().as_bytes());
}
3 => {
let raw = reader.read_exact(8)?;
let mut arr = [0u8; 8];
arr.copy_from_slice(raw);
let value = f64::from_le_bytes(arr);
out.extend_from_slice(value.to_string().as_bytes());
}
_ => return Err(Error::Unsupported("float byte width not supported")),
},
NUM_SIGNED => {
let bytes = match byte_code {
0 => 1,
1 => 2,
2 => 4,
3 => 8,
4 => 16,
_ => return Err(Error::Unsupported("signed width not supported")),
};
let raw = reader.read_exact(bytes)?;
let mut buf = [0u8; 16];
buf[..bytes].copy_from_slice(raw);
if (raw[bytes - 1] & 0x80) != 0 && bytes < 16 {
for b in &mut buf[bytes..] {
*b = 0xFF;
}
}
let value = i128::from_le_bytes(buf);
out.extend_from_slice(value.to_string().as_bytes());
}
NUM_UNSIGNED => {
let bytes = match byte_code {
0 => 1,
1 => 2,
2 => 4,
3 => 8,
4 => 16,
_ => return Err(Error::Unsupported("unsigned width not supported")),
};
let raw = reader.read_exact(bytes)?;
let mut buf = [0u8; 16];
buf[..bytes].copy_from_slice(raw);
let value = u128::from_le_bytes(buf);
out.extend_from_slice(value.to_string().as_bytes());
}
_ => return Err(Error::InvalidHeader(header)),
}
Ok(())
}
fn write_object(
reader: &mut BeveReader<'_>,
out: &mut Vec<u8>,
header: u8,
depth: usize,
) -> Result<()> {
let key_type = parse_subtype(header);
if key_type != KEY_STRING {
return Err(Error::Unsupported(
"json conversion supports string keys only",
));
}
let len = reader.read_size()? as usize;
out.push(b'{');
for i in 0..len {
if i > 0 {
out.push(b',');
}
let key_len = reader.read_size()? as usize;
let key_bytes = reader.read_exact(key_len)?;
let key = str::from_utf8(key_bytes)
.map_err(|_| Error::InvalidType("invalid utf-8 in object key"))?;
write_json_string(out, key);
out.push(b':');
write_value(reader, out, depth + 1)?;
}
out.push(b'}');
Ok(())
}
fn write_typed_array(reader: &mut BeveReader<'_>, out: &mut Vec<u8>, header: u8) -> Result<()> {
let value_type = parse_subtype(header);
let byte_code = parse_byte_count_code(header);
out.push(b'[');
match value_type {
ARRAY_FLOAT => write_typed_float_array(reader, out, byte_code)?,
ARRAY_SIGNED => write_typed_signed_array(reader, out, byte_code)?,
ARRAY_UNSIGNED => write_typed_unsigned_array(reader, out, byte_code)?,
ARRAY_BOOL_OR_STRING => {
if byte_code == 0 {
write_typed_bool_array(reader, out)?;
} else {
write_typed_string_array(reader, out)?;
}
}
_ => return Err(Error::InvalidHeader(header)),
}
out.push(b']');
Ok(())
}
fn write_typed_unsigned_array(
reader: &mut BeveReader<'_>,
out: &mut Vec<u8>,
byte_code: u8,
) -> Result<()> {
let bytes_per = match byte_code {
0 => 1,
1 => 2,
2 => 4,
3 => 8,
4 => 16,
_ => return Err(Error::Unsupported("unsigned width not supported")),
};
let len = reader.read_size()? as usize;
for i in 0..len {
if i > 0 {
out.push(b',');
}
let raw = reader.read_exact(bytes_per)?;
let mut buf = [0u8; 16];
buf[..bytes_per].copy_from_slice(raw);
let value = u128::from_le_bytes(buf);
out.extend_from_slice(value.to_string().as_bytes());
}
Ok(())
}
fn write_typed_signed_array(
reader: &mut BeveReader<'_>,
out: &mut Vec<u8>,
byte_code: u8,
) -> Result<()> {
let bytes_per = match byte_code {
0 => 1,
1 => 2,
2 => 4,
3 => 8,
4 => 16,
_ => return Err(Error::Unsupported("signed width not supported")),
};
let len = reader.read_size()? as usize;
for i in 0..len {
if i > 0 {
out.push(b',');
}
let raw = reader.read_exact(bytes_per)?;
let mut buf = [0u8; 16];
buf[..bytes_per].copy_from_slice(raw);
if bytes_per < 16 && (raw[bytes_per - 1] & 0x80) != 0 {
for b in &mut buf[bytes_per..] {
*b = 0xFF;
}
}
let value = i128::from_le_bytes(buf);
out.extend_from_slice(value.to_string().as_bytes());
}
Ok(())
}
fn write_typed_float_array(
reader: &mut BeveReader<'_>,
out: &mut Vec<u8>,
byte_code: u8,
) -> Result<()> {
let len = reader.read_size()? as usize;
for i in 0..len {
if i > 0 {
out.push(b',');
}
let value = match byte_code {
0 => {
let raw = reader.read_exact(2)?;
let bits = u16::from_le_bytes([raw[0], raw[1]]);
bf16::from_bits(bits).to_f32() as f64
}
1 => {
let raw = reader.read_exact(2)?;
let bits = u16::from_le_bytes([raw[0], raw[1]]);
f16::from_bits(bits).to_f32() as f64
}
2 => {
let raw = reader.read_exact(4)?;
let mut arr = [0u8; 4];
arr.copy_from_slice(raw);
f32::from_le_bytes(arr) as f64
}
3 => {
let raw = reader.read_exact(8)?;
let mut arr = [0u8; 8];
arr.copy_from_slice(raw);
f64::from_le_bytes(arr)
}
_ => return Err(Error::Unsupported("float width not supported")),
};
out.extend_from_slice(value.to_string().as_bytes());
}
Ok(())
}
fn write_typed_bool_array(reader: &mut BeveReader<'_>, out: &mut Vec<u8>) -> Result<()> {
let len = reader.read_size()? as usize;
let packed = len.div_ceil(8);
let bytes = reader.read_exact(packed)?;
for idx in 0..len {
if idx > 0 {
out.push(b',');
}
let byte = bytes[idx / 8];
let bit = idx % 8;
if (byte & (1 << bit)) != 0 {
out.extend_from_slice(b"true");
} else {
out.extend_from_slice(b"false");
}
}
Ok(())
}
fn write_typed_string_array(reader: &mut BeveReader<'_>, out: &mut Vec<u8>) -> Result<()> {
let len = reader.read_size()? as usize;
for i in 0..len {
if i > 0 {
out.push(b',');
}
let slen = reader.read_size()? as usize;
let bytes = reader.read_exact(slen)?;
let s = str::from_utf8(bytes)
.map_err(|_| Error::InvalidType("invalid utf-8 in typed string array"))?;
write_json_string(out, s);
}
Ok(())
}
fn write_extension(
reader: &mut BeveReader<'_>,
out: &mut Vec<u8>,
header: u8,
depth: usize,
) -> Result<()> {
let ext_id = parse_extension_id(header);
match ext_id {
EXT_DELIMITER => {
out.push(b'\n');
}
EXT_TYPE_TAG => {
skip_value(reader, depth + 1)?;
write_value(reader, out, depth + 1)?;
}
EXT_COMPLEX => write_complex_extension(reader, out)?,
EXT_MATRICES => write_matrix_extension(reader, out, depth)?,
_ => {
return Err(Error::Unsupported(
"extension not supported for JSON conversion",
));
}
}
Ok(())
}
#[derive(Clone, Copy)]
enum ComplexNumeric {
Float,
Signed,
Unsigned,
}
enum ComplexValue {
Float(f64),
Signed(i128),
Unsigned(u128),
}
impl ComplexValue {
fn write_json(&self, out: &mut Vec<u8>) {
match self {
ComplexValue::Float(v) => out.extend_from_slice(v.to_string().as_bytes()),
ComplexValue::Signed(v) => out.extend_from_slice(v.to_string().as_bytes()),
ComplexValue::Unsigned(v) => out.extend_from_slice(v.to_string().as_bytes()),
}
}
}
fn parse_complex_header_byte(header: u8) -> Result<(bool, ComplexNumeric, u8)> {
let form = header & 0x07;
let is_array = match form {
0 => false,
1 => true,
_ => return Err(Error::Unsupported("complex extension form not supported")),
};
let numeric = match (header >> 3) & 0x03 {
NUM_FLOAT => ComplexNumeric::Float,
NUM_SIGNED => ComplexNumeric::Signed,
NUM_UNSIGNED => ComplexNumeric::Unsigned,
_ => {
return Err(Error::Unsupported(
"complex extension numeric type not supported",
));
}
};
let byte_code = (header >> 5) & 0x07;
Ok((is_array, numeric, byte_code))
}
fn complex_elem_len(kind: ComplexNumeric, byte_code: u8) -> Result<usize> {
match kind {
ComplexNumeric::Float => match byte_code {
0 | 1 => Ok(2),
2 => Ok(4),
3 => Ok(8),
_ => Err(Error::Unsupported("complex float width unsupported")),
},
ComplexNumeric::Signed | ComplexNumeric::Unsigned => match byte_code {
0 => Ok(1),
1 => Ok(2),
2 => Ok(4),
3 => Ok(8),
4 => Ok(16),
_ => Err(Error::Unsupported("complex width not supported")),
},
}
}
fn write_complex_extension(reader: &mut BeveReader<'_>, out: &mut Vec<u8>) -> Result<()> {
let header = reader.read_byte()?;
let (is_array, numeric, byte_code) = parse_complex_header_byte(header)?;
if !is_array {
let re = read_complex_component(reader, numeric, byte_code)?;
let im = read_complex_component(reader, numeric, byte_code)?;
out.push(b'[');
re.write_json(out);
out.push(b',');
im.write_json(out);
out.push(b']');
} else {
let len = reader.read_size()? as usize;
out.push(b'[');
for i in 0..len {
if i > 0 {
out.push(b',');
}
let re = read_complex_component(reader, numeric, byte_code)?;
let im = read_complex_component(reader, numeric, byte_code)?;
out.push(b'[');
re.write_json(out);
out.push(b',');
im.write_json(out);
out.push(b']');
}
out.push(b']');
}
Ok(())
}
fn read_complex_component(
reader: &mut BeveReader<'_>,
kind: ComplexNumeric,
byte_code: u8,
) -> Result<ComplexValue> {
match kind {
ComplexNumeric::Float => {
let value = match byte_code {
0 => {
let raw = reader.read_exact(2)?;
let bits = u16::from_le_bytes([raw[0], raw[1]]);
bf16::from_bits(bits).to_f32() as f64
}
1 => {
let raw = reader.read_exact(2)?;
let bits = u16::from_le_bytes([raw[0], raw[1]]);
f16::from_bits(bits).to_f32() as f64
}
2 => {
let raw = reader.read_exact(4)?;
let mut arr = [0u8; 4];
arr.copy_from_slice(raw);
f32::from_le_bytes(arr) as f64
}
3 => {
let raw = reader.read_exact(8)?;
let mut arr = [0u8; 8];
arr.copy_from_slice(raw);
f64::from_le_bytes(arr)
}
_ => return Err(Error::Unsupported("complex float width unsupported")),
};
Ok(ComplexValue::Float(value))
}
ComplexNumeric::Signed => {
let elem_bytes = complex_elem_len(kind, byte_code)?;
let raw = reader.read_exact(elem_bytes)?;
let mut buf = [0u8; 16];
buf[..elem_bytes].copy_from_slice(raw);
if elem_bytes < 16 && (raw[elem_bytes - 1] & 0x80) != 0 {
for b in &mut buf[elem_bytes..] {
*b = 0xFF;
}
}
let value = i128::from_le_bytes(buf);
Ok(ComplexValue::Signed(value))
}
ComplexNumeric::Unsigned => {
let elem_bytes = complex_elem_len(kind, byte_code)?;
let raw = reader.read_exact(elem_bytes)?;
let mut buf = [0u8; 16];
buf[..elem_bytes].copy_from_slice(raw);
let value = u128::from_le_bytes(buf);
Ok(ComplexValue::Unsigned(value))
}
}
}
fn write_matrix_extension(
reader: &mut BeveReader<'_>,
out: &mut Vec<u8>,
depth: usize,
) -> Result<()> {
let header = reader.read_byte()?;
let layout = if (header & 0x01) != 0 {
"layout_left"
} else {
"layout_right"
};
out.extend_from_slice(b"{\"layout\":");
write_json_string(out, layout);
out.extend_from_slice(b",\"extents\":");
write_value(reader, out, depth + 1)?;
out.extend_from_slice(b",\"value\":");
write_value(reader, out, depth + 1)?;
out.push(b'}');
Ok(())
}
fn skip_value(reader: &mut BeveReader<'_>, depth: usize) -> Result<()> {
if depth >= MAX_RECURSION_DEPTH {
return Err(Error::Unsupported("beve recursion depth exceeded"));
}
let header = reader.read_byte()?;
let ty = parse_type(header);
match ty {
TYPE_NULL_BOOL => {}
TYPE_NUMBER => {
let byte_code = parse_byte_count_code(header);
let len = match parse_subtype(header) {
NUM_FLOAT => match byte_code {
0 | 1 => 2,
2 => 4,
3 => 8,
_ => return Err(Error::Unsupported("float width not supported")),
},
NUM_SIGNED | NUM_UNSIGNED => match byte_code {
0 => 1,
1 => 2,
2 => 4,
3 => 8,
4 => 16,
_ => return Err(Error::Unsupported("integer width not supported")),
},
_ => return Err(Error::InvalidHeader(header)),
};
reader.read_exact(len)?;
}
TYPE_STRING => {
let len = reader.read_size()? as usize;
reader.read_exact(len)?;
}
TYPE_OBJECT => {
let len = reader.read_size()? as usize;
for _ in 0..len {
let key_len = reader.read_size()? as usize;
reader.read_exact(key_len)?;
skip_value(reader, depth + 1)?;
}
}
TYPE_GENERIC_ARRAY => {
let len = reader.read_size()? as usize;
for _ in 0..len {
skip_value(reader, depth + 1)?;
}
}
TYPE_TYPED_ARRAY => {
let value_type = parse_subtype(header);
let byte_code = parse_byte_count_code(header);
match value_type {
ARRAY_FLOAT => {
let len = reader.read_size()? as usize;
let elem_bytes: usize = match byte_code {
0 | 1 => 2usize,
2 => 4usize,
3 => 8usize,
_ => return Err(Error::Unsupported("float width not supported")),
};
let total = len.checked_mul(elem_bytes).ok_or(Error::InvalidSize)?;
reader.read_exact(total)?;
}
ARRAY_SIGNED | ARRAY_UNSIGNED => {
let len = reader.read_size()? as usize;
let elem_bytes: usize = match byte_code {
0 => 1usize,
1 => 2usize,
2 => 4usize,
3 => 8usize,
4 => 16usize,
_ => return Err(Error::Unsupported("integer width not supported")),
};
let total = len.checked_mul(elem_bytes).ok_or(Error::InvalidSize)?;
reader.read_exact(total)?;
}
ARRAY_BOOL_OR_STRING => {
if byte_code == 0 {
let len = reader.read_size()? as usize;
let packed = len.div_ceil(8);
reader.read_exact(packed)?;
} else {
let len = reader.read_size()? as usize;
for _ in 0..len {
let slen = reader.read_size()? as usize;
reader.read_exact(slen)?;
}
}
}
_ => return Err(Error::InvalidHeader(header)),
}
}
TYPE_EXTENSION => {
let ext_id = parse_extension_id(header);
match ext_id {
EXT_DELIMITER => {}
EXT_TYPE_TAG => {
skip_value(reader, depth + 1)?;
skip_value(reader, depth + 1)?;
}
EXT_COMPLEX => {
let ch = reader.read_byte()?;
let (is_array, numeric, byte_code) = parse_complex_header_byte(ch)?;
let elem_bytes = complex_elem_len(numeric, byte_code)?;
if !is_array {
let total = elem_bytes.checked_mul(2usize).ok_or(Error::InvalidSize)?;
reader.read_exact(total)?;
} else {
let len = reader.read_size()? as usize;
let total = elem_bytes
.checked_mul(2usize)
.and_then(|v| v.checked_mul(len))
.ok_or(Error::InvalidSize)?;
reader.read_exact(total)?;
}
}
EXT_MATRICES => {
reader.read_byte()?; skip_value(reader, depth + 1)?;
skip_value(reader, depth + 1)?;
}
_ => {
return Err(Error::Unsupported(
"extension not supported for JSON conversion",
));
}
}
}
_ => return Err(Error::InvalidHeader(header)),
}
Ok(())
}
fn write_json_string(out: &mut Vec<u8>, value: &str) {
out.push(b'"');
let bytes = value.as_bytes();
let mut start = 0;
for (idx, &b) in bytes.iter().enumerate() {
let escape = match b {
b'"' => Some(b'"'),
b'\\' => Some(b'\\'),
b'\n' => Some(b'n'),
b'\r' => Some(b'r'),
b'\t' => Some(b't'),
b'\x08' => Some(b'b'),
b'\x0C' => Some(b'f'),
_ if b < 0x20 => None,
_ => continue,
};
if let Some(esc) = escape {
if start < idx {
out.extend_from_slice(&bytes[start..idx]);
}
out.extend_from_slice(&[b'\\', esc]);
start = idx + 1;
} else if b < 0x20 {
if start < idx {
out.extend_from_slice(&bytes[start..idx]);
}
out.extend_from_slice(b"\\u00");
let hi = b >> 4;
let lo = b & 0x0F;
out.push(nibble_to_hex(hi));
out.push(nibble_to_hex(lo));
start = idx + 1;
}
}
if start < bytes.len() {
out.extend_from_slice(&bytes[start..]);
}
out.push(b'"');
}
fn nibble_to_hex(n: u8) -> u8 {
match n {
0..=9 => b'0' + n,
10..=15 => b'a' + (n - 10),
_ => b'0',
}
}