use super::types::{Color, Priority};
use tinyklv::dec::binary as decb;
use tinyklv::enc::binary as encb;
use tinyklv::prelude::*;
use std::rc::Rc;
use std::sync::Arc;
fn enc_u8_ref(v: &u8) -> Vec<u8> {
encb::u8(*v)
}
fn enc_u16_owned(v: u16) -> Vec<u8> {
encb::be_u16(v)
}
fn enc_str_ref(s: &str) -> Vec<u8> {
let mut out = encb::u8_from_usize(s.len());
out.extend_from_slice(s.as_bytes());
out
}
fn enc_bytes_ref(b: &[u8]) -> Vec<u8> {
let mut out = encb::u8_from_usize(b.len());
out.extend_from_slice(b);
out
}
fn dec_u8_len_string(input: &mut &[u8]) -> tinyklv::Result<String> {
let len = decb::u8(input)? as usize;
let (head, rest) = input.split_at(len);
*input = rest;
Ok(String::from_utf8_lossy(head).into_owned())
}
fn dec_u8_len_bytes(input: &mut &[u8]) -> tinyklv::Result<Vec<u8>> {
let len = decb::u8(input)? as usize;
let (head, rest) = input.split_at(len);
*input = rest;
Ok(head.to_vec())
}
#[derive(Klv, Debug, Clone, PartialEq)]
#[klv(
sentinel = b"\x00\x00\x00\x01",
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
)]
struct AllSigils {
#[klv(
key = 0x01,
dec = decb::u8,
enc = enc_u8_ref,
)]
count: u8,
#[klv(
key = 0x02,
dec = Color::decode_value,
enc = Color::encode_value,
)]
color: Color,
#[klv(
key = 0x03,
dec = decb::be_u16,
enc = *enc_u16_owned,
)]
id: u16,
#[klv(
key = 0x04,
dec = dec_u8_len_string,
enc = &enc_str_ref,
)]
label: String,
#[klv(
key = 0x05,
dec = dec_u8_len_bytes,
enc = &enc_bytes_ref,
)]
blob: Vec<u8>,
}
#[test]
fn all_sigils_roundtrip() {
let original = AllSigils {
count: 42,
color: Color::Blue,
id: 0x1234,
label: String::from("sigil"),
blob: vec![0xDE, 0xAD, 0xBE, 0xEF],
};
let bytes = original.encode_frame();
let mut slice = bytes.as_slice();
let decoded = AllSigils::decode_frame(&mut slice).expect("decode_frame");
assert_eq!(original, decoded);
}
#[derive(Klv, Debug, Clone, PartialEq)]
#[klv(
sentinel = b"\x00\x00\x00\x02",
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
)]
struct AllSigilsOptional {
#[klv(
key = 0x01,
dec = decb::u8,
enc = enc_u8_ref,
)]
count: Option<u8>,
#[klv(
key = 0x02,
dec = Color::decode_value,
enc = Color::encode_value,
)]
color: Option<Color>,
#[klv(
key = 0x03,
dec = decb::be_u16,
enc = *enc_u16_owned,
)]
id: Option<u16>,
#[klv(
key = 0x04,
dec = dec_u8_len_string,
enc = &enc_str_ref,
)]
label: Option<String>,
#[klv(
key = 0x05,
dec = dec_u8_len_bytes,
enc = &enc_bytes_ref,
)]
blob: Option<Vec<u8>>,
}
#[test]
fn all_sigils_optional_all_present() {
let original = AllSigilsOptional {
count: Some(7),
color: Some(Color::Red),
id: Some(0xCAFE),
label: Some(String::from("hi")),
blob: Some(vec![1, 2, 3]),
};
let bytes = original.encode_frame();
let mut slice = bytes.as_slice();
let decoded = AllSigilsOptional::decode_frame(&mut slice).expect("decode_frame");
assert_eq!(original, decoded);
}
#[test]
fn all_sigils_optional_all_absent() {
let original = AllSigilsOptional {
count: None,
color: None,
id: None,
label: None,
blob: None,
};
let bytes = original.encode_frame();
let mut slice = bytes.as_slice();
let decoded = AllSigilsOptional::decode_frame(&mut slice).expect("decode_frame");
assert_eq!(original, decoded);
}
#[test]
fn all_sigils_optional_partial() {
let original = AllSigilsOptional {
count: Some(99),
color: None,
id: Some(0x0042),
label: Some(String::from("partial")),
blob: None,
};
let bytes = original.encode_frame();
let mut slice = bytes.as_slice();
let decoded = AllSigilsOptional::decode_frame(&mut slice).expect("decode_frame");
assert_eq!(original, decoded);
}
fn enc_inner_u32_ref(v: &u32) -> Vec<u8> {
encb::be_u32(*v)
}
fn enc_inner_str_ref(s: &str) -> Vec<u8> {
let mut out = encb::u8_from_usize(s.len());
out.extend_from_slice(s.as_bytes());
out
}
fn dec_box_u32(input: &mut &[u8]) -> tinyklv::Result<Box<u32>> {
decb::be_u32(input).map(Box::new)
}
fn dec_rc_u32(input: &mut &[u8]) -> tinyklv::Result<Rc<u32>> {
decb::be_u32(input).map(Rc::new)
}
fn dec_arc_str(input: &mut &[u8]) -> tinyklv::Result<Arc<str>> {
let len = decb::u8(input)? as usize;
let (head, rest) = input.split_at(len);
*input = rest;
Ok(Arc::from(String::from_utf8_lossy(head).as_ref()))
}
#[derive(Klv, Debug, Clone, PartialEq)]
#[klv(
sentinel = b"\x00\x00\x00\x03",
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
)]
struct SmartPointerSigils {
#[klv(
key = 0x01,
dec = dec_box_u32,
enc = &enc_inner_u32_ref,
)]
boxed: Box<u32>,
#[klv(
key = 0x02,
dec = dec_rc_u32,
enc = &enc_inner_u32_ref,
)]
counted: Rc<u32>,
#[klv(
key = 0x03,
dec = dec_arc_str,
enc = &enc_inner_str_ref,
)]
shared: Arc<str>,
}
#[test]
fn smart_pointer_sigils_roundtrip() {
let original = SmartPointerSigils {
boxed: Box::new(0xAABBCCDD),
counted: Rc::new(0x11223344),
shared: Arc::from("arc"),
};
let bytes = original.encode_frame();
let mut slice = bytes.as_slice();
let decoded = SmartPointerSigils::decode_frame(&mut slice).expect("decode_frame");
assert_eq!(original, decoded);
}
#[derive(Klv, Debug, Clone, PartialEq)]
#[klv(
sentinel = b"\x00\x00\x00\x04",
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
)]
struct SigilMixture {
#[klv(
key = 0x01,
dec = decb::u8,
enc = enc_u8_ref,
)]
a: u8,
#[klv(
key = 0x02,
dec = decb::u8,
enc = *encb::u8,
)]
b: u8,
#[klv(
key = 0x03,
dec = Priority::decode_value,
enc = Priority::encode_value,
)]
pri: Priority,
#[klv(
key = 0x04,
dec = Color::decode_value,
enc = Color::encode_value,
)]
col: Color,
#[klv(
key = 0x05,
dec = dec_u8_len_string,
enc = &enc_str_ref,
)]
label: String,
}
#[test]
fn sigil_mixture_roundtrip() {
let original = SigilMixture {
a: 1,
b: 2,
pri: Priority::High,
col: Color::Green,
label: String::from("mix"),
};
let bytes = original.encode_frame();
let mut slice = bytes.as_slice();
let decoded = SigilMixture::decode_frame(&mut slice).expect("decode_frame");
assert_eq!(original, decoded);
}