use byteorder::BigEndian;
use byteorder::ReadBytesExt;
use core::fmt;
use std::io::Cursor;
pub const MSG_RELIABLE: u8 = 0x40;
pub const MSG_RESENT: u8 = 0x20;
pub const MSG_ZEROCODED: u8 = 0x80;
pub const MSG_APPENDED_ACKS: u8 = 0x10;
#[derive(Debug, Clone, Default)]
pub struct Header {
pub reliable: bool,
pub resent: bool,
pub zerocoded: bool,
pub appended_acks: bool,
pub sequence_number: u32,
pub id: u16,
pub frequency: PacketFrequency,
pub ack_list: Option<Vec<u32>>,
pub size: Option<usize>,
}
impl Header {
pub fn try_from_bytes(bytes: &[u8]) -> Result<Header, std::io::Error> {
let mut cursor = Cursor::new(bytes);
let flags = cursor.read_u8()?;
let appended_acks = (flags & MSG_APPENDED_ACKS) != 0;
let reliable = (flags & MSG_RELIABLE) != 0;
let resent = (flags & MSG_RESENT) != 0;
let zerocoded = (flags & MSG_ZEROCODED) != 0;
let sequence_number = cursor.read_u32::<BigEndian>()?;
let _extra_info = cursor.read_u8()?;
let (frequency, id) = match cursor.read_u8()? {
255 => match cursor.read_u8()? {
255 => match cursor.read_u8()? {
255 => {
let fixed = cursor.read_u8()?;
(PacketFrequency::Fixed, fixed as u16)
}
low => {
let mut high = cursor.read_u8()?;
if zerocoded && low == 0 && high == 1 {
high = cursor.read_u8()?;
}
let combined: u16 = u16::from_le_bytes([high, low]);
(PacketFrequency::Low, combined)
}
},
medium => (PacketFrequency::Medium, medium as u16),
},
high => (PacketFrequency::High, high as u16),
};
let header = Header {
appended_acks,
reliable,
resent,
zerocoded,
sequence_number,
frequency,
id,
ack_list: None,
size: Some(cursor.position() as usize),
};
Ok(header)
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(10);
let mut flags = 0;
if self.appended_acks {
flags |= MSG_APPENDED_ACKS;
}
if self.reliable {
flags |= MSG_RELIABLE;
}
if self.resent {
flags |= MSG_RESENT;
}
if self.zerocoded {
flags |= MSG_ZEROCODED;
}
bytes.push(flags);
bytes.extend_from_slice(&self.sequence_number.to_be_bytes());
bytes.push(0);
bytes.extend_from_slice(&self.frequency.to_bytes(self));
bytes
}
}
fn uint16_to_bytes_big(value: u16) -> [u8; 2] {
[(value >> 8) as u8, (value & 0xFF) as u8]
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum PacketFrequency {
High,
Medium,
Low,
#[default]
Fixed,
}
impl fmt::Display for PacketFrequency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PacketFrequency::High => write!(f, "High"),
PacketFrequency::Medium => write!(f, "Medium"),
PacketFrequency::Low => write!(f, "Low"),
PacketFrequency::Fixed => write!(f, "Fixed"),
}
}
}
impl PacketFrequency {
pub fn to_bytes(&self, header: &Header) -> Vec<u8> {
let mut bytes = Vec::new();
match self {
PacketFrequency::High => {
bytes.push(header.id as u8);
}
PacketFrequency::Medium => {
bytes.push(0xFF);
bytes.push(header.id as u8);
}
PacketFrequency::Low => {
bytes.push(0xFF);
bytes.push(0xFF);
let id_bytes = uint16_to_bytes_big(header.id);
bytes.extend_from_slice(&id_bytes);
}
PacketFrequency::Fixed => {
bytes.push(0xFF);
bytes.push(0xFF);
bytes.push(0xFF);
bytes.push(header.id as u8); }
};
bytes
}
}