use rust_decimal::Decimal;
use serde_json::Value as JsonValue;
use super::error::DecodeError;
use super::value::{DynValue, StructValue};
use crate::typ::{EnumType, Fields, SimpleEnumType, StructType, Typ};
pub fn decode(typ: &Typ, bytes: &[u8]) -> Result<DynValue, DecodeError> {
let mut r = Reader::new(bytes);
let v = read_value(typ, &mut r)?;
if r.pos != bytes.len() {
return Err(DecodeError::TrailingBytes {
decoded: r.pos,
total: bytes.len(),
});
}
Ok(v)
}
struct Reader<'a> {
buf: &'a [u8],
pos: usize,
}
impl<'a> Reader<'a> {
fn new(buf: &'a [u8]) -> Self {
Self { buf, pos: 0 }
}
fn take(&mut self, n: usize) -> Result<&'a [u8], DecodeError> {
let end = self.pos.checked_add(n).ok_or(DecodeError::UnexpectedEof {
offset: self.pos,
need: n,
})?;
if end > self.buf.len() {
return Err(DecodeError::UnexpectedEof {
offset: self.pos,
need: end - self.buf.len(),
});
}
let slice = &self.buf[self.pos..end];
self.pos = end;
Ok(slice)
}
fn u8(&mut self) -> Result<u8, DecodeError> {
Ok(self.take(1)?[0])
}
fn u16_le(&mut self) -> Result<u16, DecodeError> {
let s = self.take(2)?;
Ok(u16::from_le_bytes([s[0], s[1]]))
}
fn u32_le(&mut self) -> Result<u32, DecodeError> {
let s = self.take(4)?;
Ok(u32::from_le_bytes([s[0], s[1], s[2], s[3]]))
}
fn u64_le(&mut self) -> Result<u64, DecodeError> {
let s = self.take(8)?;
let mut arr = [0u8; 8];
arr.copy_from_slice(s);
Ok(u64::from_le_bytes(arr))
}
fn i32_le(&mut self) -> Result<i32, DecodeError> {
Ok(self.u32_le()? as i32)
}
fn i64_le(&mut self) -> Result<i64, DecodeError> {
Ok(self.u64_le()? as i64)
}
fn f32_le(&mut self) -> Result<f32, DecodeError> {
Ok(f32::from_bits(self.u32_le()?))
}
fn f64_le(&mut self) -> Result<f64, DecodeError> {
Ok(f64::from_bits(self.u64_le()?))
}
fn len_prefixed_bytes(&mut self) -> Result<Vec<u8>, DecodeError> {
let n = self.u32_le()? as usize;
Ok(self.take(n)?.to_vec())
}
}
fn read_value(typ: &Typ, r: &mut Reader<'_>) -> Result<DynValue, DecodeError> {
Ok(match typ {
Typ::Void => DynValue::Void,
Typ::Bool => DynValue::Bool(r.u8()? != 0),
Typ::U8 => DynValue::U8(r.u8()?),
Typ::U16 => DynValue::U16(r.u16_le()?),
Typ::U32 => DynValue::U32(r.u32_le()?),
Typ::U64 => DynValue::U64(r.u64_le()?),
Typ::I32 => DynValue::I32(r.i32_le()?),
Typ::I64 => DynValue::I64(r.i64_le()?),
Typ::F32 => DynValue::F32(r.f32_le()?),
Typ::F64 => DynValue::F64(r.f64_le()?),
Typ::Str => {
let bytes = r.len_prefixed_bytes()?;
let s =
String::from_utf8(bytes).map_err(|_| DecodeError::InvalidUtf8 { offset: r.pos })?;
DynValue::Str(s)
}
Typ::Datetime => DynValue::Datetime(r.i64_le()?),
Typ::Timestamp => DynValue::Timestamp(r.u64_le()?),
Typ::Decimal => {
let slice = r.take(16)?;
let mut arr = [0u8; 16];
arr.copy_from_slice(slice);
DynValue::Decimal(Decimal::deserialize(arr))
}
Typ::Id32 => DynValue::Id32(r.u32_le()?),
Typ::Id64 => DynValue::Id64(r.u64_le()?),
Typ::Fuid => DynValue::Fuid(r.u64_le()?),
Typ::LowId => DynValue::LowId(r.u32_le()?),
Typ::Bytes => DynValue::Bytes(r.len_prefixed_bytes()?),
Typ::ArrayBytes(n) => DynValue::ArrayBytes(r.take(*n as usize)?.to_vec()),
Typ::Array(n, inner) => {
let mut out = Vec::with_capacity(*n as usize);
for _ in 0..*n {
out.push(read_value(inner, r)?);
}
DynValue::Array(out)
}
Typ::Vec(inner) => {
let n = r.u32_le()? as usize;
let mut out = Vec::with_capacity(n);
for _ in 0..n {
out.push(read_value(inner, r)?);
}
DynValue::Vec(out)
}
Typ::Optional(inner) => {
if r.u8()? == 0 {
DynValue::Optional(None)
} else {
DynValue::Optional(Some(Box::new(read_value(inner, r)?)))
}
}
Typ::SimpleEnum(SimpleEnumType { name, variants }) => {
let offset = r.pos;
let tag = r.u8()?;
let variant_name = variants
.iter()
.find(|(t, _)| *t == tag)
.map(|(_, n)| *n)
.ok_or(DecodeError::UnknownVariant { tag, offset })?;
DynValue::SimpleEnum {
name,
variant: tag,
variant_name,
}
}
Typ::Struct(StructType { name, fields }) => {
let fv = match fields {
Fields::Named(arr) => {
let mut pairs = Vec::with_capacity(arr.len());
for (field_name, field_typ) in *arr {
pairs.push((*field_name, read_value(field_typ, r)?));
}
StructValue::Named(pairs)
}
Fields::Unnamed(arr) => {
let mut items = Vec::with_capacity(arr.len());
for field_typ in *arr {
items.push(read_value(field_typ, r)?);
}
StructValue::Unnamed(items)
}
};
DynValue::Struct { name, fields: fv }
}
Typ::Enum(EnumType { name, variants }) => {
let offset = r.pos;
let tag = r.u8()?;
let (_, (variant_name, variant_typ)) = variants
.iter()
.find(|(t, _)| *t == tag)
.ok_or(DecodeError::UnknownVariant { tag, offset })?;
let field = Box::new(read_value(variant_typ, r)?);
DynValue::Enum {
name,
variant: tag,
variant_name,
field,
}
}
Typ::RustJson => {
let raw = r.len_prefixed_bytes()?;
let v: JsonValue = serde_json::from_slice(&raw)
.map_err(|_| DecodeError::InvalidJson { offset: r.pos })?;
DynValue::RustJson(v)
}
Typ::JsonBytes => {
let bytes = r.len_prefixed_bytes()?;
let s =
String::from_utf8(bytes).map_err(|_| DecodeError::InvalidUtf8 { offset: r.pos })?;
DynValue::JsonBytes(s)
}
Typ::Custom(_, _) => return Err(DecodeError::CustomUnsupported),
})
}