use std::io;
use crate::beve::header::{self, byte_width};
use crate::beve::reader::{
Reader, Typed, bare_header, bf16_to_f32, complex_payload, f16_to_f32, key_width, le_u128,
payload_len, sign_extend,
};
use crate::error::{Error, ErrorCode, PResult, Result, StreamError, StreamResult};
use crate::ext::MatrixLayout;
use crate::ext::matrix::{EXTENTS_MEMBER, LAYOUT_MEMBER, VALUE_MEMBER};
use crate::json::Writer;
use crate::options::{Options, Standard};
pub fn beve_to_json(input: &[u8]) -> Result<String> {
beve_to_json_with::<Standard>(input)
}
pub fn beve_to_json_with<O: Options>(input: &[u8]) -> Result<String> {
let mut w = Writer::<O>::new();
transcode(input, &mut w)?;
Ok(w.into_string())
}
pub fn beve_to_json_into(input: &[u8], out: &mut String) -> Result<()> {
beve_to_json_into_with::<Standard>(input, out)
}
pub fn beve_to_json_into_with<O: Options>(input: &[u8], out: &mut String) -> Result<()> {
let buf = core::mem::take(out).into_bytes();
let mut w = Writer::<O>::from_vec(buf);
let result = transcode(input, &mut w);
*out = w.into_string();
result
}
pub fn beve_to_json_writer<W>(input: &[u8], out: W) -> StreamResult<()>
where
W: io::Write,
{
beve_to_json_writer_buffered(input, out, crate::json::writer::DEFAULT_SINK_BUFFER)
}
pub fn beve_to_json_writer_with<O, W>(input: &[u8], out: W) -> StreamResult<()>
where
O: Options,
W: io::Write,
{
beve_to_json_writer_buffered_with::<O, W>(input, out, crate::json::writer::DEFAULT_SINK_BUFFER)
}
pub fn beve_to_json_writer_buffered<W>(input: &[u8], out: W, buffer: usize) -> StreamResult<()>
where
W: io::Write,
{
beve_to_json_writer_buffered_with::<Standard, W>(input, out, buffer)
}
pub fn beve_to_json_writer_buffered_with<O, W>(
input: &[u8],
mut out: W,
buffer: usize,
) -> StreamResult<()>
where
O: Options,
W: io::Write,
{
let mut w = Writer::<O>::to_sink_with_capacity(&mut out, buffer);
let result = transcode(input, &mut w);
let flushed = w.finish();
result.map_err(StreamError::Parse)?;
flushed.map_err(StreamError::Io)
}
fn transcode<O: Options>(input: &[u8], w: &mut Writer<'_, O>) -> Result<()> {
let mut r = Reader::new(input);
match value(&mut r, w).and_then(|()| r.finish()) {
Ok(()) => Ok(()),
Err(code) => Err(Error::new(code, r.position())),
}
}
fn value<O: Options>(r: &mut Reader<'_>, w: &mut Writer<'_, O>) -> PResult<()> {
let h = r.head()?;
body(r, w, h)
}
fn body<O: Options>(r: &mut Reader<'_>, w: &mut Writer<'_, O>, h: u8) -> PResult<()> {
match header::ty(h) {
header::TY_NULL_BOOL => match h {
header::NULL => w.write_null(),
header::FALSE => w.write_bool(false),
header::TRUE => w.write_bool(true),
_ => return Err(ErrorCode::InvalidHeader),
},
header::TY_NUMBER => {
let cat = header::sub(h);
let code = header::count(h);
let width = header::decodable_width(cat, code)?;
let bytes = r.take(width)?;
number(w, cat, code, bytes)?;
}
header::TY_STRING => {
bare_header(h)?;
w.write_str(r.str_body()?);
}
header::TY_OBJECT => object(r, w, h)?,
header::TY_TYPED_ARRAY => typed_array(r, w, h)?,
header::TY_GENERIC_ARRAY => {
bare_header(h)?;
generic_array(r, w)?;
}
header::TY_EXTENSION => extension(r, w, h)?,
_ => return Err(ErrorCode::InvalidHeader),
}
Ok(())
}
fn extension<O: Options>(r: &mut Reader<'_>, w: &mut Writer<'_, O>, h: u8) -> PResult<()> {
match header::ext_id(h) {
header::EXT_COMPLEX => complex(r, w),
header::EXT_MATRIX => matrix(r, w),
header::EXT_DELIMITER => Err(ErrorCode::InvalidHeader),
_ => Err(ErrorCode::UnsupportedFeature),
}
}
fn complex<O: Options>(r: &mut Reader<'_>, w: &mut Writer<'_, O>) -> PResult<()> {
let (class, width, pairs) = r.complex_head()?;
let cat = header::sub(class);
let code = header::count(class);
if pairs != Some(0) {
header::decodable_width(cat, code)?;
}
let payload = r.take(complex_payload(width, pairs)?)?;
let Some(_) = pairs else {
return pair(w, cat, code, width, payload);
};
w.open(b'[');
for z in payload.chunks_exact(2 * width) {
w.item();
pair(w, cat, code, width, z)?;
w.push(b',');
}
w.close(b']');
Ok(())
}
fn pair<O: Options>(
w: &mut Writer<'_, O>,
cat: u8,
code: u8,
width: usize,
z: &[u8],
) -> PResult<()> {
w.open(b'[');
w.item();
number(w, cat, code, &z[..width])?;
w.push(b',');
w.item();
number(w, cat, code, &z[width..2 * width])?;
w.push(b',');
w.close(b']');
Ok(())
}
fn matrix<O: Options>(r: &mut Reader<'_>, w: &mut Writer<'_, O>) -> PResult<()> {
let layout = MatrixLayout::from_byte(r.take(1)?[0]).ok_or(ErrorCode::InvalidMatrixLayout)?;
r.nested(|r| {
w.open(b'{');
w.key(LAYOUT_MEMBER);
w.write_str(layout.as_str());
w.push(b',');
w.key(EXTENTS_MEMBER);
value(r, w)?;
w.push(b',');
w.key(VALUE_MEMBER);
value(r, w)?;
w.push(b',');
w.close(b'}');
Ok(())
})
}
fn half(bytes: &[u8]) -> u16 {
u16::from_le_bytes(bytes.try_into().expect("2 bytes"))
}
fn number<O: Options>(w: &mut Writer<'_, O>, cat: u8, code: u8, bytes: &[u8]) -> PResult<()> {
match cat {
header::CAT_FLOAT => match code {
0 => w.write_f32(bf16_to_f32(half(bytes))),
1 => w.write_f32(f16_to_f32(half(bytes))),
2 => w.write_f32(f32::from_le_bytes(bytes.try_into().expect("4 bytes"))),
3 => w.write_f64(f64::from_le_bytes(bytes.try_into().expect("8 bytes"))),
_ => return Err(ErrorCode::UnsupportedFeature),
},
header::CAT_UNSIGNED => w.write_u128(le_u128(bytes)),
header::CAT_SIGNED => w.write_i128_raw(sign_extend(le_u128(bytes), bytes.len())),
_ => return Err(ErrorCode::ExpectedNumber),
}
Ok(())
}
fn object<O: Options>(r: &mut Reader<'_>, w: &mut Writer<'_, O>, h: u8) -> PResult<()> {
let cat = header::sub(h);
let width = key_width(h)?;
let members = r.count()?;
r.nested(|r| {
w.open(b'{');
for _ in 0..members {
w.line();
if cat == header::CAT_FLOAT {
w.write_str(r.str_body()?);
} else {
w.push(b'"');
number(w, cat, header::count(h), r.take(width)?)?;
w.push(b'"');
}
w.colon();
value(r, w)?;
w.push(b',');
}
w.close(b'}');
Ok(())
})
}
fn generic_array<O: Options>(r: &mut Reader<'_>, w: &mut Writer<'_, O>) -> PResult<()> {
let n = r.count()?;
r.nested(|r| {
w.open(b'[');
for _ in 0..n {
w.item();
value(r, w)?;
w.push(b',');
}
w.close(b']');
Ok(())
})
}
fn typed_array<O: Options>(r: &mut Reader<'_>, w: &mut Writer<'_, O>, h: u8) -> PResult<()> {
r.nested(|r| {
w.open(b'[');
match r.typed_head(h)? {
Typed::Bools(n) => {
let payload = r.take(n.div_ceil(8))?;
for i in 0..n {
w.item();
w.write_bool((payload[i >> 3] >> (i & 7)) & 1 == 1);
w.push(b',');
}
}
Typed::Strings(n) => {
for _ in 0..n {
w.item();
w.write_str(r.str_body()?);
w.push(b',');
}
}
Typed::Fixed(elem, n) => {
let cat = header::sub(elem);
let code = header::count(elem);
let width = byte_width(cat, code).ok_or(ErrorCode::InvalidHeader)?;
if n > 0 {
header::decodable_width(cat, code)?;
}
let payload = r.take(payload_len(elem, n)?)?;
for chunk in payload.chunks_exact(width) {
w.item();
number(w, cat, code, chunk)?;
w.push(b',');
}
}
}
w.close(b']');
Ok(())
})
}