use crate::alloc_prelude::*;
use nano_leb128::ULEB128;
#[derive(Debug, Clone, PartialEq)]
pub enum ItemKey {
NoKey,
IntegerKey(u64),
StringKey(String),
BytesKey(Vec<u8>),
}
impl ItemKey {
pub fn type_bits(&self) -> u8 {
match self {
Self::NoKey => 0b00000000,
Self::IntegerKey(_) => 0b00010000,
Self::StringKey(_) => 0b00100000,
Self::BytesKey(_) => 0b00110000,
}
}
pub fn encode(&self) -> Result<Vec<u8>, crate::Error> {
let mut out: Vec<u8> = Vec::new();
let mut len_bytes = [0u8; 10];
match self {
Self::NoKey => {}
Self::IntegerKey(i) => {
let count = ULEB128::from(*i).write_into(&mut len_bytes)?;
out.extend(&len_bytes[0..count]);
}
Self::StringKey(s) => {
let b = s.as_bytes();
let count = ULEB128::from(b.len() as u64).write_into(&mut len_bytes)?;
out.extend(&len_bytes[0..count]);
out.extend(b);
}
Self::BytesKey(b) => {
let count = ULEB128::from(b.len() as u64).write_into(&mut len_bytes)?;
out.extend(&len_bytes[0..count]);
out.extend(b);
}
}
Ok(out)
}
pub fn decode(base: u8, ext: &[u8]) -> Result<(Self, usize), crate::Error> {
match base & 0b00110000 {
0b00000000 => Ok((Self::NoKey, 0)),
0b00010000 => {
let (val, len) = ULEB128::read_from(&ext)?;
let val = u64::from(val);
Ok((Self::IntegerKey(val), len))
}
0b00100000 => {
let (val, len) = ULEB128::read_from(&ext)?;
let val = u64::from(val);
let total = (val as usize) + len;
let s = String::from_utf8(Vec::from(&ext[len..total]))?;
Ok((Self::StringKey(s), total))
}
0b00110000 => {
let (val, len) = ULEB128::read_from(&ext)?;
let val = u64::from(val);
let total = (val as usize) + len;
let b = Vec::from(&ext[len..total]);
Ok((Self::BytesKey(b), total))
}
_ => unreachable!(),
}
}
}
impl From<u64> for ItemKey {
fn from(i: u64) -> ItemKey {
ItemKey::IntegerKey(i)
}
}
impl From<&str> for ItemKey {
fn from(s: &str) -> ItemKey {
ItemKey::StringKey(String::from(s))
}
}
impl From<String> for ItemKey {
fn from(s: String) -> ItemKey {
ItemKey::StringKey(s)
}
}
impl From<Vec<u8>> for ItemKey {
fn from(v: Vec<u8>) -> ItemKey {
ItemKey::BytesKey(v)
}
}
impl From<&[u8]> for ItemKey {
fn from(v: &[u8]) -> ItemKey {
ItemKey::BytesKey(Vec::from(v))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encode_key_empty() {
let key = ItemKey::NoKey;
assert_eq!(Vec::<u8>::new(), key.encode().unwrap())
}
#[test]
fn encode_key_integer() {
let key = ItemKey::IntegerKey(624485);
assert_eq!(vec![0xE5, 0x8E, 0x26], key.encode().unwrap())
}
#[test]
fn encode_key_string() {
let key = ItemKey::StringKey(String::from("A"));
assert_eq!(vec![0x01, 0x41], key.encode().unwrap())
}
#[test]
fn encode_key_bytes() {
let key = ItemKey::BytesKey(vec![0xC0, 0xFF, 0xEE]);
assert_eq!(vec![0x03, 0xC0, 0xFF, 0xEE], key.encode().unwrap())
}
#[test]
fn decode_key_empty() {
let (key, len) = ItemKey::decode(0b00000000, &[]).unwrap();
assert_eq!(key, ItemKey::NoKey);
assert_eq!(len, 0);
}
#[test]
fn decode_key_integer() {
let (key, len) = ItemKey::decode(0b00010000, &[0x01, 0x00]).unwrap();
assert_eq!(key, ItemKey::IntegerKey(1));
assert_eq!(len, 1);
let (key, len) = ItemKey::decode(0b00010000, &[0xE5, 0x8E, 0x26, 0x00]).unwrap();
assert_eq!(key, ItemKey::IntegerKey(624485));
assert_eq!(len, 3);
}
#[test]
fn decode_key_string() {
let (key, len) = ItemKey::decode(0b00100000, &[0x03, 0x41, 0x41, 0x41]).unwrap();
assert_eq!(key, ItemKey::StringKey(String::from("AAA")));
assert_eq!(len, 4);
}
#[test]
fn decode_key_bytes() {
let (key, len) = ItemKey::decode(0b00110000, &[0x03, 0xC0, 0xFF, 0xEE]).unwrap();
assert_eq!(key, ItemKey::BytesKey(vec![0xC0, 0xFF, 0xEE]));
assert_eq!(len, 4);
}
}