pub const HEADER_SIZE: usize = 8;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum MessageType {
Control = 0,
}
impl MessageType {
pub fn from_u8(v: u8) -> Option<Self> {
match v {
0 => Some(MessageType::Control),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Header {
pub payload_length: u32,
pub priority: u8,
pub message_type: MessageType,
}
impl Header {
pub fn encode(&self) -> [u8; HEADER_SIZE] {
let mut buf = [0u8; HEADER_SIZE];
buf[0..4].copy_from_slice(&self.payload_length.to_le_bytes());
buf[4] = self.priority;
buf[5] = self.message_type as u8;
buf
}
pub fn decode(buf: &[u8; HEADER_SIZE]) -> Option<Self> {
let payload_length = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
let priority = buf[4];
let message_type = MessageType::from_u8(buf[5])?;
Some(Header {
payload_length,
priority,
message_type,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_roundtrip() {
let h = Header {
payload_length: 12345,
priority: 2,
message_type: MessageType::Control,
};
let encoded = h.encode();
let decoded = Header::decode(&encoded).unwrap();
assert_eq!(h, decoded);
}
#[test]
fn test_header_control_type() {
let h = Header {
payload_length: 100,
priority: 0,
message_type: MessageType::Control,
};
let enc = h.encode();
assert_eq!(enc[5], 0u8);
let dec = Header::decode(&enc).unwrap();
assert_eq!(dec.message_type, MessageType::Control);
}
#[test]
fn test_header_max_payload() {
let h = Header {
payload_length: u32::MAX,
priority: 0,
message_type: MessageType::Control,
};
let enc = h.encode();
let dec = Header::decode(&enc).unwrap();
assert_eq!(dec.payload_length, u32::MAX);
}
#[test]
fn test_header_invalid_message_type() {
let mut buf = [0u8; HEADER_SIZE];
buf[5] = 255; assert!(Header::decode(&buf).is_none());
}
#[test]
fn test_header_reserved_bytes_zeroed() {
let h = Header {
payload_length: 42,
priority: 1,
message_type: MessageType::Control,
};
let enc = h.encode();
assert_eq!(enc[6], 0);
assert_eq!(enc[7], 0);
}
#[test]
fn test_message_type_from_u8() {
assert_eq!(MessageType::from_u8(0), Some(MessageType::Control));
assert_eq!(MessageType::from_u8(1), None);
}
}