use super::types::*;
use tinyklv::dec::binary as decb;
use tinyklv::enc::binary as encb;
use tinyklv::prelude::*;
#[derive(Klv, Debug, PartialEq)]
#[klv(
stream = &[u8],
sentinel = b"\xBE\xEF",
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
trait_fallback,
)]
struct NavPacket {
#[klv(key = 0x01)]
position: Coordinate,
#[klv(key = 0x02)]
velocity: Velocity,
}
impl Default for NavPacket {
fn default() -> NavPacket {
NavPacket {
position: Coordinate {
lat: 37.7749,
lon: -122.4194,
},
velocity: Velocity {
dx: 10,
dy: -5,
dz: 0,
},
}
}
}
#[derive(Klv, Debug, PartialEq)]
#[klv(
stream = &[u8],
sentinel = b"\xCA\xFE",
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
trait_fallback,
)]
struct WeatherPacket {
#[klv(key = 0x01)]
priority: Priority,
#[klv(key = 0x02)]
sky_color: Color,
}
impl Default for WeatherPacket {
fn default() -> WeatherPacket {
WeatherPacket {
priority: Priority::High,
sky_color: Color::Blue,
}
}
}
#[derive(Debug, PartialEq)]
enum Packet {
Nav(NavPacket),
Weather(WeatherPacket),
}
fn dispatch_one(input: &mut &[u8]) -> Option<Packet> {
if input.len() < 2 {
*input = &[];
return None;
}
match &input[0..2] {
b"\xBE\xEF" => NavPacket::decode_frame(input).ok().map(Packet::Nav),
b"\xCA\xFE" => WeatherPacket::decode_frame(input).ok().map(Packet::Weather),
_ => {
*input = &input[1..];
None
}
}
}
#[test]
fn dispatch_by_sentinel() {
let nav = NavPacket::default();
let weather = WeatherPacket::default();
let mut stream: Vec<u8> = nav.encode_frame();
stream.extend(weather.encode_frame());
let mut slice = stream.as_slice();
let mut packets: Vec<Packet> = Vec::new();
while !slice.is_empty() {
if let Some(p) = dispatch_one(&mut slice) {
packets.push(p);
}
}
assert_eq!(packets.len(), 2);
assert_eq!(packets[0], Packet::Nav(nav));
assert_eq!(packets[1], Packet::Weather(weather));
}
#[test]
fn dispatch_nav_then_weather_then_nav() {
let n1 = NavPacket::default();
let w1 = WeatherPacket::default();
let n2 = NavPacket {
position: Coordinate {
lat: 51.5074,
lon: -0.1278,
},
velocity: Velocity {
dx: 0,
dy: 0,
dz: 1,
},
};
let mut stream: Vec<u8> = n1.encode_frame();
stream.extend(w1.encode_frame());
stream.extend(n2.encode_frame());
let mut slice = stream.as_slice();
let mut packets: Vec<Packet> = Vec::new();
while !slice.is_empty() {
if let Some(p) = dispatch_one(&mut slice) {
packets.push(p);
}
}
assert_eq!(packets.len(), 3);
assert!(matches!(&packets[0], Packet::Nav(_)));
assert!(matches!(&packets[1], Packet::Weather(_)));
assert!(matches!(&packets[2], Packet::Nav(_)));
}
#[test]
fn dispatch_unknown_sentinel_skips_byte() {
let nav = NavPacket::default();
let mut stream: Vec<u8> = vec![0xDE, 0xAD];
stream.extend(nav.encode_frame());
let mut slice = stream.as_slice();
let mut packets: Vec<Packet> = Vec::new();
while !slice.is_empty() {
if let Some(p) = dispatch_one(&mut slice) {
packets.push(p);
}
}
assert_eq!(packets.len(), 1, "garbage bytes skipped, NavPacket decoded");
assert_eq!(packets[0], Packet::Nav(nav));
}
#[test]
fn dispatch_all_unknown_returns_empty() {
let stream: &[u8] = &[0x00, 0x11, 0x22, 0x33, 0x44];
let mut slice = stream;
let mut packets: Vec<Packet> = Vec::new();
while !slice.is_empty() {
if let Some(p) = dispatch_one(&mut slice) {
packets.push(p);
}
}
assert!(packets.is_empty(), "no recognised sentinels -> no packets");
}
#[test]
fn dispatch_empty_stream() {
let mut slice: &[u8] = &[];
let result = dispatch_one(&mut slice);
assert!(result.is_none());
}