use crate::alloc_prelude::*;
use crate::datatypes::*;
use crate::{ItemKey, ItemValue, ItemHeader};
#[derive(Debug, Clone, PartialEq)]
pub struct Item {
pub key: ItemKey,
pub value: ItemValue,
}
impl Item {
pub fn new(key: ItemKey, value: ItemValue) -> Self {
Self { key, value }
}
pub fn with_key(mut self, key: ItemKey) -> Self {
self.key = key;
self
}
pub fn encode(&self) -> Result<Vec<u8>, crate::Error> {
let (data_type, mut value_enc) = self.value.encode()?;
if data_type == DataType::Null {
value_enc.clear();
}
let header = ItemHeader::new(
data_type,
self.key.clone(),
data_type == DataType::Null,
value_enc.len() as u64,
);
let header_enc = header.encode()?;
let mut out: Vec<u8> = Vec::new();
out.extend(&header_enc);
out.extend(&value_enc);
Ok(out)
}
pub fn decode(input: &[u8]) -> Result<(Item, usize), crate::Error> {
let mut count: usize = 0;
let (hdr, hdr_count) = ItemHeader::decode(&input[count..])?;
count += hdr_count;
let (val, val_count) = ItemValue::decode(&hdr, &input[count..])?;
count += val_count;
let item = Item::new(hdr.key, val);
Ok((item, count))
}
}
impl From<Vec<u8>> for Item {
fn from(v: Vec<u8>) -> Item {
Item::new(ItemKey::NoKey, ItemValue::Bytes(v))
}
}
impl From<&[u8]> for Item {
fn from(v: &[u8]) -> Item {
Item::new(ItemKey::NoKey, ItemValue::Bytes(Vec::from(v)))
}
}
impl From<String> for Item {
fn from(s: String) -> Item {
Item::new(ItemKey::NoKey, ItemValue::UTF8(s))
}
}
impl From<&str> for Item {
fn from(s: &str) -> Item {
Item::new(ItemKey::NoKey, ItemValue::UTF8(String::from(s)))
}
}
impl From<bool> for Item {
fn from(b: bool) -> Item {
Item::new(ItemKey::NoKey, ItemValue::Boolean(b))
}
}
impl From<u32> for Item {
fn from(i: u32) -> Item {
Item::new(ItemKey::NoKey, ItemValue::UVarInt(i as u64))
}
}
impl From<u64> for Item {
fn from(i: u64) -> Item {
Item::new(ItemKey::NoKey, ItemValue::UVarInt(i))
}
}
impl From<i32> for Item {
fn from(i: i32) -> Item {
Item::new(ItemKey::NoKey, ItemValue::SVarInt(i as i64))
}
}
impl From<i64> for Item {
fn from(i: i64) -> Item {
Item::new(ItemKey::NoKey, ItemValue::SVarInt(i))
}
}
impl From<f64> for Item {
fn from(i: f64) -> Item {
Item::new(ItemKey::NoKey, ItemValue::Float64(i))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encode_boolean_true() {
let item = Item::new(
ItemKey::StringKey(String::from("A")),
ItemValue::Boolean(true),
);
let out = item.encode().unwrap();
assert_eq!(out, vec![0b01100101, 0x01, 0x41, 0x01, 0x01]);
}
#[test]
fn decode_boolean_true() {
let data = vec![0b01100101, 0x01, 0x41, 0x01, 0x01];
let (item, count) = Item::decode(&data).unwrap();
assert_eq!(count, data.len());
assert_eq!(item.key, ItemKey::StringKey(String::from("A")));
assert_eq!(item.value, ItemValue::Boolean(true));
}
#[test]
fn encode_composite_list_recursive() {
let val = Item::new(ItemKey::NoKey, ItemValue::Boolean(true));
let l_val = vec![val.clone(), val.clone()];
let inner = Item::new(ItemKey::NoKey, ItemValue::CompositeList(l_val));
let l_inner = vec![inner.clone(), inner.clone()];
let item = Item::new(ItemKey::NoKey, ItemValue::CompositeList(l_inner));
let res = item.encode().unwrap();
assert_eq!(
res,
vec![
0b01000010, 0x10, 0b01000010, 0x06, 0b01000101, 0x01, 0x01, 0b01000101, 0x01, 0x01, 0b01000010, 0x06, 0b01000101, 0x01, 0x01, 0b01000101, 0x01, 0x01, ]
);
}
#[test]
fn decode_composite_list_recursive() {
let data = vec![
0b01000010, 0x10, 0b01000010, 0x06, 0b01000101, 0x01, 0x01, 0b01000101, 0x01, 0x01, 0b01000010, 0x06, 0b01000101, 0x01, 0x01, 0b01000101, 0x01, 0x01, ];
let (item, count) = Item::decode(&data).unwrap();
assert_eq!(count, data.len());
let outer = item.value.get_entries().unwrap();
assert_eq!(outer.len(), 2);
let mid = outer[0].value.get_entries().unwrap();
assert_eq!(mid.len(), 2);
let inner = mid[0].value.get_bool();
assert_eq!(inner, Some(true));
}
#[test]
fn encode_composite_dict_recursive() {
let val = Item::new(ItemKey::IntegerKey(2), ItemValue::Boolean(true));
let l_val = vec![val.clone(), val.clone()];
let inner = Item::new(ItemKey::IntegerKey(1), ItemValue::CompositeDict(l_val));
let l_inner = vec![inner.clone(), inner.clone()];
let item = Item::new(ItemKey::NoKey, ItemValue::CompositeDict(l_inner));
let res = item.encode().unwrap();
assert_eq!(
res,
vec![
0b01000001, 0x16, 0b01010001, 0x01, 0x08, 0b01010101, 0x02, 0x01, 0x01, 0b01010101, 0x02, 0x01, 0x01, 0b01010001, 0x01, 0x08, 0b01010101, 0x02, 0x01, 0x01, 0b01010101, 0x02, 0x01, 0x01, ]
);
}
#[test]
fn decode_composite_dict_recursive() {
let data = vec![
0b01000001, 0x16, 0b01010001, 0x01, 0x08, 0b01010101, 0x02, 0x01, 0x01, 0b01010101, 0x02, 0x01, 0x01, 0b01010001, 0x01, 0x08, 0b01010101, 0x02, 0x01, 0x01, 0b01010101, 0x02, 0x01, 0x01, ];
let (item, count) = Item::decode(&data).unwrap();
assert_eq!(count, data.len());
let outer = item.value.get_entries().unwrap();
assert_eq!(outer.len(), 2);
let mid = outer[0].value.get_entries().unwrap();
assert_eq!(mid.len(), 2);
let inner = mid[0].value.get_bool();
assert_eq!(inner, Some(true));
}
}