use tinyklv::dec::binary as decb;
use tinyklv::enc::binary as encb;
use tinyklv::prelude::*;
use tinyklv::Klv;
#[derive(Debug, PartialEq, Clone)]
struct Id(u16);
impl tinyklv::DecodeValue<&[u8]> for Id {
fn decode_value(input: &mut &[u8]) -> tinyklv::Result<Self> {
Ok(Id(decb::be_u16(input)?))
}
}
impl tinyklv::EncodeValue<Vec<u8>> for Id {
fn encode_value(&self) -> Vec<u8> {
encb::be_u16(self.0)
}
}
#[derive(Debug, PartialEq, Clone)]
enum Mode {
A,
B,
}
impl tinyklv::DecodeValue<&[u8]> for Mode {
fn decode_value(input: &mut &[u8]) -> tinyklv::Result<Self> {
let b = decb::u8(input)?;
match b {
0 => Ok(Mode::A),
1 => Ok(Mode::B),
_ => Err(::tinyklv::__export::winnow::error::ContextError::new()),
}
}
}
impl tinyklv::EncodeValue<Vec<u8>> for Mode {
fn encode_value(&self) -> Vec<u8> {
match self {
Mode::A => vec![0],
Mode::B => vec![1],
}
}
}
#[derive(Klv, Debug, PartialEq, Clone)]
#[klv(
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
trait_fallback,
)]
struct Inner {
#[klv(
key = 0x11,
dec = decb::be_u16,
enc = *encb::be_u16,
)]
value: u16,
}
#[derive(Klv, Debug, PartialEq, Clone)]
#[klv(
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
trait_fallback,
)]
struct OuterFallback {
#[klv(key = 0x01)]
id: Id,
#[klv(key = 0x02)]
mode: Mode,
#[klv(key = 0x03)]
opt_id: Option<Id>,
#[klv(key = 0x04)]
inner: Inner,
}
#[test]
fn fallback_leaf_struct_roundtrip() {
let original = OuterFallback {
id: Id(0xBEEF),
mode: Mode::A,
opt_id: Some(Id(42)),
inner: Inner { value: 0x1234 },
};
let encoded = original.encode_value();
let decoded = OuterFallback::decode_value(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn fallback_enum_roundtrip() {
for mode in [Mode::A, Mode::B] {
let original = OuterFallback {
id: Id(1),
mode: mode.clone(),
opt_id: None,
inner: Inner { value: 0 },
};
let encoded = original.encode_value();
let decoded = OuterFallback::decode_value(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded.mode, mode);
}
}
#[test]
fn fallback_option_none() {
let original = OuterFallback {
id: Id(7),
mode: Mode::B,
opt_id: None,
inner: Inner { value: 0xAA },
};
let mut encoded = Vec::new();
encoded.push(0x01);
encoded.push(2);
encoded.extend(Id(7).encode_value());
encoded.push(0x02);
encoded.push(1);
encoded.extend(Mode::B.encode_value());
let inner_bytes = (Inner { value: 0xAA }).encode_value();
encoded.push(0x04);
encoded.push(inner_bytes.len() as u8);
encoded.extend(inner_bytes);
let decoded = OuterFallback::decode_value(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn fallback_nested_derived_roundtrip() {
let original = OuterFallback {
id: Id(u16::MAX),
mode: Mode::A,
opt_id: Some(Id(u16::MIN)),
inner: Inner { value: 0xCAFE },
};
let encoded = original.encode_value();
let decoded = OuterFallback::decode_value(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded.inner.value, 0xCAFE);
assert_eq!(decoded, original);
}
fn custom_id_dec(input: &mut &[u8]) -> tinyklv::Result<Id> {
let raw = decb::be_u16(input)?;
Ok(Id(raw ^ 0xFFFF))
}
fn custom_id_enc(id: &Id) -> Vec<u8> {
encb::be_u16(id.0 ^ 0xFFFF)
}
#[derive(Klv, Debug, PartialEq)]
#[klv(
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
trait_fallback,
)]
struct PrecedenceField {
#[klv(
key = 0x01,
dec = custom_id_dec,
enc = custom_id_enc,
)]
custom: Id,
#[klv(key = 0x02)]
fallback: Id,
}
#[test]
fn fallback_precedence_field_xcoder_beats_fallback() {
let original = PrecedenceField {
custom: Id(0x1234),
fallback: Id(0x5678),
};
let encoded = original.encode_value();
let decoded = PrecedenceField::decode_value(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded, original);
let custom_key_pos = encoded.iter().position(|&b| b == 0x01).unwrap();
let custom_bytes = &encoded[custom_key_pos + 2..custom_key_pos + 4];
assert_eq!(custom_bytes, &[0xED, 0xCB]); }
#[derive(Klv, Debug, PartialEq)]
#[klv(
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
default(typ = Id, dec = custom_id_dec, enc = custom_id_enc),
trait_fallback,
)]
struct PrecedenceDefault {
#[klv(key = 0x01)]
via_default: Id,
}
#[test]
fn fallback_precedence_default_beats_fallback() {
let original = PrecedenceDefault {
via_default: Id(0xABCD),
};
let encoded = original.encode_value();
let key_pos = encoded.iter().position(|&b| b == 0x01).unwrap();
assert_eq!(&encoded[key_pos + 2..key_pos + 4], &[0x54, 0x32]); let decoded = PrecedenceDefault::decode_value(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded, original);
}