use super::decoder::Decoder;
use super::encoder::Encoder;
use super::TryFromValue;
use std::borrow::Cow;
use std::collections::BTreeMap;
pub type Int = i64;
pub type Str<'a> = Cow<'a, [u8]>;
pub type List<'a> = Vec<Value<'a>>;
pub type Dict<'a> = BTreeMap<Cow<'a, [u8]>, Value<'a>>;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Value<'a> {
Int(Int),
Str(Str<'a>),
List(List<'a>),
Dict(Dict<'a>),
}
impl<'a> Value<'a> {
pub fn get<'b, T: TryFromValue<'b>>(&'b self, key: &'static str) -> Option<T> {
let x = self.try_into::<&'b Dict<'b>>()?;
let x = x.get(key.as_bytes())?;
x.try_into()
}
pub fn try_into<'b, T: TryFromValue<'b>>(&'b self) -> Option<T> {
T::try_from(self)
}
pub fn encode(&self) -> Vec<u8> {
let mut v = Vec::with_capacity(1500);
let mut e = Encoder::new(&mut v);
e.value(self);
v
}
pub fn encode_into(&self, buf: &mut Vec<u8>) {
let mut e = Encoder::new(buf);
e.clear();
e.value(self);
}
pub fn decode(buf: &'a [u8], max_allocs: usize) -> Option<Self> {
Decoder::new(buf, max_allocs).take_value()
}
pub fn into_owned(self) -> Value<'static> {
match self {
Value::Int(i) => Value::Int(i),
Value::Str(s) => Value::Str(Cow::Owned(s.into_owned())),
Value::List(l) => Value::List(l.into_iter().map(Value::into_owned).collect()),
Value::Dict(d) => {
Value::Dict(d.into_iter().map(|(k, v)| (Cow::Owned(k.into_owned()), v.into_owned())).collect())
}
}
}
}
impl std::fmt::Debug for Value<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Int(i) => write!(f, "{}", i),
Value::Str(s) => match std::str::from_utf8(s) {
Ok(s) => write!(f, "{:?}", s),
Err(_) => {
for i in s.iter() {
write!(f, "{:02x}", i)?;
}
Ok(())
}
},
Value::List(l) => f.debug_list().entries(l.iter()).finish(),
Value::Dict(d) => f
.debug_map()
.entries(d.iter().map(|(k, v)| {
let k = match std::str::from_utf8(k) {
Ok(s) => s.to_string(),
Err(_) => format!("{:?}", k),
};
(k, v)
}))
.finish(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_int_01() {
let value = Value::Int(0);
let encoded = value.encode();
assert_eq!(&encoded, b"i0e");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_int_02() {
let value = Value::Int(1);
let encoded = value.encode();
assert_eq!(&encoded, b"i1e");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_int_03() {
let value = Value::Int(-1);
let encoded = value.encode();
assert_eq!(&encoded, b"i-1e");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_int_04() {
let value = Value::Int(10);
let encoded = value.encode();
assert_eq!(&encoded, b"i10e");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_int_05() {
let value = Value::Int(-10);
let encoded = value.encode();
assert_eq!(&encoded, b"i-10e");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_int_06() {
let value = Value::Int(42);
let encoded = value.encode();
assert_eq!(&encoded, b"i42e");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_int_07() {
let value = Value::Int(-42);
let encoded = value.encode();
assert_eq!(&encoded, b"i-42e");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_str_01() {
let value = Value::Str(Cow::Borrowed(b""));
let encoded = value.encode();
assert_eq!(&encoded, b"0:");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_str_02() {
let value = Value::Str(Cow::Borrowed(b":"));
let encoded = value.encode();
assert_eq!(&encoded, b"1::");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_str_03() {
let value = Value::Str(Cow::Borrowed(b"hello"));
let encoded = value.encode();
assert_eq!(&encoded, b"5:hello");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_str_04() {
let value = Value::Str(Cow::Borrowed(b"helloworld"));
let encoded = value.encode();
assert_eq!(&encoded, b"10:helloworld");
let value_ = Value::decode(&encoded, 0);
assert_eq!(value_, Some(value));
}
#[test]
fn test_list_01() {
let value = Value::List(vec![]);
let encoded = value.encode();
assert_eq!(&encoded, b"le");
let value_ = Value::decode(&encoded, 10);
assert_eq!(value_, Some(value));
}
#[test]
fn test_list_02() {
let value = Value::List(vec![Value::Int(42), Value::Str(Cow::Borrowed(b"hello"))]);
let encoded = value.encode();
assert_eq!(&encoded, b"li42e5:helloe");
let value_ = Value::decode(&encoded, 10);
assert_eq!(value_, Some(value));
}
#[test]
fn test_dict_01() {
let value = Value::Dict(BTreeMap::new());
let encoded = value.encode();
assert_eq!(&encoded, b"de");
let value_ = Value::decode(&encoded, 10);
assert_eq!(value_, Some(value));
}
#[test]
fn test_dict_02() {
let mut dict = BTreeMap::new();
dict.insert(b"age".into(), Value::Int(42));
dict.insert(b"name".into(), Value::Str(Cow::Borrowed(b"John")));
let value = Value::Dict(dict);
let encoded = value.encode();
assert_eq!(&encoded, b"d3:agei42e4:name4:Johne");
let value_ = Value::decode(&encoded, 10);
assert_eq!(value_, Some(value));
}
#[test]
fn test_dict_03_reversed_order() {
let mut dict = BTreeMap::new();
dict.insert(b"name".into(), Value::Str(Cow::Borrowed(b"John")));
dict.insert(b"age".into(), Value::Int(42));
let value = Value::Dict(dict);
let encoded = b"d4:name4:John3:agei42ee";
let value_ = Value::decode(encoded.as_ref(), 10);
assert_eq!(value_, Some(value));
}
#[test]
fn test_dict_04_duplicate_keys() {
let encoded = b"d3:agei30e3:agei40ee";
let value = Value::decode(encoded.as_ref(), 10);
assert!(value.is_none());
}
#[test]
fn test_max_alloc_int() {
let encoded = b"i42e";
let value = Value::decode(encoded.as_ref(), 0);
assert!(value.is_some());
}
#[test]
fn test_max_alloc_str() {
let encoded = b"5:hello";
let value_ = Value::decode(encoded.as_ref(), 0);
assert!(value_.is_some());
}
#[test]
fn test_max_alloc_list_empty() {
let encoded = b"le";
let value = Value::decode(encoded.as_ref(), 0);
assert!(value.is_some());
}
#[test]
fn test_max_alloc_list_one() {
let encoded = b"li42ee";
let value = Value::decode(encoded.as_ref(), 0);
assert!(value.is_none());
let value = Value::decode(encoded.as_ref(), 1);
assert!(value.is_some());
}
#[test]
fn test_max_alloc_list_two() {
let encoded = b"li1ei2ee";
let value = Value::decode(encoded.as_ref(), 1);
assert!(value.is_none());
let value = Value::decode(encoded.as_ref(), 2);
assert!(value.is_some());
}
#[test]
fn test_max_alloc_dict_empty() {
let encoded = b"de";
let value = Value::decode(encoded.as_ref(), 0);
assert!(value.is_some());
}
#[test]
fn test_max_alloc_dict_one() {
let encoded = b"d3:agei42ee";
let value = Value::decode(encoded.as_ref(), 0);
assert!(value.is_none());
let value = Value::decode(encoded.as_ref(), 1);
assert!(value.is_some());
}
#[test]
fn test_max_alloc_dict_two() {
let encoded = b"d3:agei42e4:name4:Johne";
let value = Value::decode(encoded.as_ref(), 1);
assert!(value.is_none());
let value = Value::decode(encoded.as_ref(), 2);
assert!(value.is_some());
}
}