#![allow(dead_code)]
use crate::alloc_prelude::*;
use crate::datatypes::*;
use crate::{Item, ItemHeader, ItemKey};
use core::convert::TryInto;
use nano_leb128::{SLEB128, ULEB128};
#[derive(Debug, Clone, PartialEq)]
pub enum ItemValue {
Null,
CompositeList(Vec<Item>),
CompositeDict(Vec<Item>),
Bytes(Vec<u8>),
UTF8(String),
Boolean(bool),
Int64(i64),
UVarInt(u64),
SVarInt(i64),
Float64(f64),
Stamp64(i64),
UnknownType(u64, Vec<u8>),
}
impl ItemValue {
pub fn data_type(&self) -> DataType {
match self {
Self::Null => DataType::Null,
Self::CompositeList(_) => DataType::from(KnownType::CompositeList),
Self::CompositeDict(_) => DataType::from(KnownType::CompositeDict),
Self::Bytes(_) => DataType::from(KnownType::Bytes),
Self::UTF8(_) => DataType::from(KnownType::UTF8),
Self::Boolean(_) => DataType::from(KnownType::Boolean),
Self::Int64(_) => DataType::from(KnownType::Int64),
Self::UVarInt(_) => DataType::from(KnownType::UVarInt),
Self::SVarInt(_) => DataType::from(KnownType::SVarInt),
Self::Float64(_) => DataType::from(KnownType::Float64),
Self::Stamp64(_) => DataType::from(KnownType::Stamp64),
Self::UnknownType(u, _) => DataType::from(*u),
}
}
pub fn encode(&self) -> Result<(DataType, Vec<u8>), crate::Error> {
let mut out: Vec<u8> = Vec::new();
match self {
Self::Null => {}
Self::CompositeList(items) => {
for itm in items {
out.extend(itm.encode()?);
}
}
Self::CompositeDict(items) => {
for itm in items {
if itm.key == ItemKey::NoKey {
return Err(crate::Error::DictItemWithoutKeyError);
}
out.extend(itm.encode()?);
}
}
Self::Bytes(b) => {
out.extend(b);
}
Self::UTF8(s) => {
out.extend(s.as_bytes());
}
Self::Boolean(b) => {
if *b {
out.push(0x01);
}
}
Self::Int64(i) => {
out.extend(&i.to_le_bytes());
}
Self::UVarInt(v) => {
let mut tmp = [0u8; 10];
let count = ULEB128::from(*v).write_into(&mut tmp)?;
out.extend(&tmp[0..count]);
}
Self::SVarInt(v) => {
let mut tmp = [0u8; 10];
let count = SLEB128::from(*v).write_into(&mut tmp)?;
out.extend(&tmp[0..count]);
}
Self::Float64(f) => {
out.extend(&f.to_le_bytes());
}
Self::Stamp64(i) => {
out.extend(&i.to_le_bytes());
}
Self::UnknownType(_, b) => {
out.extend(b);
}
}
Ok((self.data_type(), out))
}
pub fn decode(header: &ItemHeader, data: &[u8]) -> Result<(Self, usize), crate::Error> {
let data_len = header.data_len as usize;
let mut count: usize = 0;
if header.data_type == DataType::Null {
return Ok((Self::Null, 0));
}
if let DataType::StandardType(ty) = header.data_type {
match ty {
KnownType::CompositeList => {
if data.len() < data_len {
return Err(crate::Error::UnexpectedEof);
}
let mut items: Vec<Item> = Vec::new();
while count < data_len {
let (itm, itm_count) = Item::decode(&data[count..])?;
count += itm_count;
items.push(itm);
}
return Ok((Self::CompositeList(items), count));
}
KnownType::CompositeDict => {
if data.len() < data_len {
return Err(crate::Error::UnexpectedEof);
}
let mut items: Vec<Item> = Vec::new();
while count < data_len {
let (itm, itm_count) = Item::decode(&data[count..])?;
items.push(itm);
count += itm_count;
}
return Ok((Self::CompositeDict(items), count));
}
KnownType::Bytes => {
if data.len() < data_len {
return Err(crate::Error::UnexpectedEof);
}
let b = Vec::from(&data[..data_len]);
count += b.len();
return Ok((Self::Bytes(b), count));
}
KnownType::UTF8 => {
if data.len() < data_len {
return Err(crate::Error::UnexpectedEof);
}
let b = Vec::from(&data[..data_len]);
count += b.len();
let s = String::from_utf8(b)?;
return Ok((Self::UTF8(s), count));
}
KnownType::Boolean => {
if data_len == 0 {
return Ok((Self::Boolean(false), 0));
}
if data.len() < 1 {
return Err(crate::Error::UnexpectedEof);
}
let b = data[0] == 0x01;
count += 1;
return Ok((Self::Boolean(b), count));
}
KnownType::Int64 => {
if data_len == 0 {
return Ok((Self::Int64(0i64), 0));
}
if data.len() < 8 {
return Err(crate::Error::UnexpectedEof);
}
let b =
i64::from_le_bytes(data[0..8].try_into().expect("failed to get [u8; 8]"));
count += 8;
return Ok((Self::Int64(b), count));
}
KnownType::UVarInt => {
let (val, len) = ULEB128::read_from(&data[0..data_len])?;
count += len;
return Ok((Self::UVarInt(u64::from(val)), count));
}
KnownType::SVarInt => {
let (val, len) = SLEB128::read_from(&data[0..data_len])?;
count += len;
return Ok((Self::SVarInt(i64::from(val)), count));
}
KnownType::Float64 => {
if data_len == 0 {
return Ok((Self::Float64(0.0f64), 0));
}
if data.len() < 8 {
return Err(crate::Error::UnexpectedEof);
}
let b =
f64::from_le_bytes(data[0..8].try_into().expect("failed to get [u8; 8]"));
count += 8;
return Ok((Self::Float64(b), count));
}
_ => {
return Err(crate::Error::UnimplementedB3TypeError);
}
}
}
return Err(crate::Error::UnimplementedB3TypeError);
}
pub fn get_entries(&self) -> Option<Vec<Item>> {
match self {
Self::CompositeList(i) => Some(i.clone()),
Self::CompositeDict(i) => Some(i.clone()),
_ => None,
}
}
pub fn get_bytes(&self) -> Option<Vec<u8>> {
match self {
Self::Bytes(b) => Some(b.clone()),
_ => None,
}
}
pub fn get_utf8(&self) -> Option<String> {
match self {
Self::UTF8(s) => Some(s.clone()),
_ => None,
}
}
pub fn get_bool(&self) -> Option<bool> {
match self {
Self::Boolean(b) => Some(*b),
_ => None,
}
}
pub fn get_i64(&self) -> Option<i64> {
match self {
Self::Int64(i) => Some(*i),
Self::SVarInt(i) => Some(*i),
Self::Stamp64(i) => Some(*i),
_ => None,
}
}
pub fn get_u64(&self) -> Option<u64> {
match self {
Self::UVarInt(i) => Some(*i),
_ => None,
}
}
pub fn get_f64(&self) -> Option<f64> {
match self {
Self::Float64(i) => Some(*i),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn header_kt(kt: KnownType, data: &[u8]) -> ItemHeader {
ItemHeader::new(DataType::from(kt), ItemKey::NoKey, false, data.len() as u64)
}
#[test]
fn encode_composite_list() {
let list_entry = Item::new(ItemKey::NoKey, ItemValue::Boolean(true));
let (ty, val) = ItemValue::CompositeList(vec![list_entry.clone(), list_entry.clone()])
.encode()
.unwrap();
assert_eq!(ty, DataType::from(KnownType::CompositeList));
assert_eq!(val, vec![0b01000101, 0x01, 0x01, 0b01000101, 0x01, 0x01]);
}
#[test]
fn encode_composite_dict_fails_with_missing_key() {
let dict_entry = Item::new(ItemKey::NoKey, ItemValue::Boolean(true));
let err = ItemValue::CompositeDict(vec![dict_entry])
.encode()
.err()
.unwrap();
assert_eq!(err, crate::Error::DictItemWithoutKeyError);
}
#[test]
fn encode_composite_dict() {
let dict_ent_one = Item::new(ItemKey::IntegerKey(1), ItemValue::Boolean(true));
let dict_ent_two = Item::new(ItemKey::IntegerKey(2), ItemValue::Boolean(true));
let (ty, val) = ItemValue::CompositeDict(vec![dict_ent_one, dict_ent_two])
.encode()
.unwrap();
assert_eq!(ty, DataType::from(KnownType::CompositeDict));
assert_eq!(
val,
vec![0b01010101, 0x01, 0x01, 0x01, 0b01010101, 0x02, 0x01, 0x01]
);
}
#[test]
fn encode_boolean_false() {
let (ty, val) = ItemValue::Boolean(false).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::Boolean));
assert_eq!(val.len(), 0);
}
#[test]
fn encode_boolean_true() {
let (ty, val) = ItemValue::Boolean(true).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::Boolean));
assert_eq!(val, vec![0x01]);
}
#[test]
fn decode_boolean_false_compact() {
let data = vec![];
let header = header_kt(KnownType::Boolean, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Boolean(false));
assert_eq!(count, data.len());
}
#[test]
fn decode_boolean_false() {
let data = vec![0x00u8];
let header = header_kt(KnownType::Boolean, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Boolean(false));
assert_eq!(count, data.len());
}
#[test]
fn decode_boolean_true() {
let data = vec![0x01u8];
let header = header_kt(KnownType::Boolean, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Boolean(true));
assert_eq!(count, data.len());
}
#[test]
fn encode_bytes() {
let (ty, val) = ItemValue::Bytes(vec![0xC0, 0xFF, 0xEE]).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::Bytes));
assert_eq!(val, vec![0xC0, 0xFF, 0xEE]);
}
#[test]
fn decode_bytes_empty() {
let data = vec![];
let header = header_kt(KnownType::Bytes, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Bytes(data));
assert_eq!(count, 0);
}
#[test]
fn decode_bytes() {
let data = vec![0xC0, 0xFF, 0xEE];
let header = header_kt(KnownType::Bytes, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Bytes(data));
assert_eq!(count, 3);
}
#[test]
fn encode_utf8() {
let (ty, val) = ItemValue::UTF8(String::from("AAA")).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::UTF8));
assert_eq!(val, vec![0x41, 0x41, 0x41]);
}
#[test]
fn decode_utf8_empty() {
let data = vec![];
let header = header_kt(KnownType::UTF8, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::UTF8(String::new()));
assert_eq!(count, 0);
}
#[test]
fn decode_utf8() {
let data = vec![0x41, 0x41, 0x41];
let header = header_kt(KnownType::UTF8, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::UTF8(String::from("AAA")));
assert_eq!(count, 3);
}
#[test]
fn encode_int64() {
let (ty, val) = ItemValue::Int64(0x1234567890123456i64).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::Int64));
assert_eq!(val, vec![0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]);
let (ty, val) = ItemValue::Int64(0).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::Int64));
assert_eq!(val, vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
}
#[test]
fn decode_int64_empty() {
let data = vec![];
let header = header_kt(KnownType::Int64, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Int64(0i64));
assert_eq!(count, 0);
}
#[test]
fn decode_int64() {
let data = vec![0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12];
let header = header_kt(KnownType::Int64, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Int64(0x1234567890123456i64));
assert_eq!(count, 8);
let data = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let header = header_kt(KnownType::Int64, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Int64(0i64));
assert_eq!(count, 8);
}
#[test]
fn encode_uvarint() {
let (ty, val) = ItemValue::UVarInt(127).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::UVarInt));
assert_eq!(val, vec![0x7F]);
let (ty, val) = ItemValue::UVarInt(62451).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::UVarInt));
assert_eq!(val, vec![0xF3, 0xE7, 0x03]);
}
#[test]
fn decode_uvarint() {
let data = vec![0xF3, 0xE7, 0x03];
let header = header_kt(KnownType::UVarInt, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::UVarInt(62451));
assert_eq!(count, 3);
let data = vec![0x7F];
let header = header_kt(KnownType::UVarInt, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::UVarInt(127));
assert_eq!(count, 1);
}
#[test]
fn encode_svarint() {
let (ty, val) = ItemValue::SVarInt(128).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::SVarInt));
assert_eq!(val, vec![0x80, 0x01]);
let (ty, val) = ItemValue::SVarInt(-62541).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::SVarInt));
assert_eq!(val, vec![0xB3, 0x97, 0x7C]);
}
#[test]
fn decode_svarint() {
let data = vec![0xB3, 0x97, 0x7C];
let header = header_kt(KnownType::SVarInt, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::SVarInt(-62541));
assert_eq!(count, 3);
let data = vec![0x80, 0x01];
let header = header_kt(KnownType::SVarInt, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::SVarInt(128));
assert_eq!(count, 2);
}
#[test]
fn encode_float64() {
let (ty, val) = ItemValue::Float64(-1.0).encode().unwrap();
assert_eq!(ty, DataType::from(KnownType::Float64));
assert_eq!(val, vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBF]);
}
#[test]
fn decode_float64_empty() {
let data = vec![];
let header = header_kt(KnownType::Float64, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Float64(0.0));
assert_eq!(count, 0);
}
#[test]
fn decode_float64() {
let data = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBF];
let header = header_kt(KnownType::Float64, &data);
let (val, count) = ItemValue::decode(&header, &data).unwrap();
assert_eq!(val, ItemValue::Float64(-1.0));
assert_eq!(count, 8);
}
}