pub struct Packet<'a>(pub &'a [u8]);
pub enum PacketKind {
Standard,
Heartbeat,
EndOfSession,
}
pub const END_OF_SESSION_IDENT: u16 = u16::MAX;
pub const HEARTBEAT_IDENT: u16 = 0;
pub struct Message<'a>(pub &'a [u8]);
pub enum SessionStatus {
Active,
Inactive,
}
impl<'a> Packet<'a> {
pub const fn new(bytes: &'a [u8]) -> Packet<'a> {
debug_assert!(bytes.len() >= Self::MIN_PACKET_LEN);
Packet(bytes)
}
pub(crate) const MIN_PACKET_LEN: usize = 20;
#[inline]
pub const fn session_ident(&self) -> &'a str {
match self.0.split_at(10).0 {
bytes => match std::str::from_utf8(bytes) {
Ok(s) => s,
Err(_) => panic!("invalid UTF-8 in session"),
},
}
}
#[inline]
pub fn session_ident_raw(&self) -> &'a [u8; 10] {
self.0.split_at(10).0.try_into().unwrap()
}
#[inline]
pub const fn session_status(&self) -> SessionStatus {
match self.msg_count() {
END_OF_SESSION_IDENT => SessionStatus::Inactive,
_ => SessionStatus::Active,
}
}
#[inline]
pub const fn seq_num(&self) -> u64 {
u64::from_be_bytes([
self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15], self.0[16],
self.0[17],
])
}
#[inline]
pub const fn msg_count(&self) -> u16 {
u16::from_be_bytes([self.0[18], self.0[19]])
}
#[inline]
pub const fn messages(&self) -> &'a [u8] {
self.0.split_at(20).1
}
#[inline]
pub const fn packet_kind(&self) -> PacketKind {
use PacketKind as PK;
match self.msg_count() {
HEARTBEAT_IDENT => PK::Heartbeat,
END_OF_SESSION_IDENT => PK::EndOfSession,
_ => PK::Standard,
}
}
#[inline]
pub const fn iter(&self) -> Messages<'a> {
Messages {
bytes: self.messages(),
remaining: match self.msg_count() {
END_OF_SESSION_IDENT | HEARTBEAT_IDENT => 0,
n => n,
},
}
}
}
impl<'a> IntoIterator for &Packet<'a> {
type Item = Message<'a>;
type IntoIter = Messages<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> Message<'a> {
#[inline]
pub const fn length(&self) -> u16 {
u16::from_be_bytes([self.0[0], self.0[1]])
}
#[inline]
pub const fn data(&self) -> &'a [u8] {
self.0.split_at(2).1
}
}
pub struct Messages<'a> {
bytes: &'a [u8],
remaining: u16,
}
impl<'a> Iterator for Messages<'a> {
type Item = Message<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 || self.bytes.len() < 2 {
return None;
}
let len = u16::from_be_bytes([self.bytes[0], self.bytes[1]]) as usize;
let total = 2 + len;
if self.bytes.len() < total {
return None; }
let (block, rest) = self.bytes.split_at(total);
self.bytes = rest;
self.remaining -= 1;
Some(Message(block))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.remaining as usize;
(n, Some(n))
}
}
impl<'a> ExactSizeIterator for Messages<'a> {}