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 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> {}
use std::array;
pub(crate) struct Request([u8; 20]);
impl Request {
#[inline]
pub(crate) fn new(session_ident: &str, seq_num: u64, msg_count: u16) -> Request {
let mut buf: [u8; 20] = array::repeat(0);
let bytes = session_ident.as_bytes();
let end = Self::SESSION_OFFSET + std::cmp::min(session_ident.len(), Self::SESSION_LENGTH);
buf[Self::SESSION_OFFSET..end].copy_from_slice(bytes);
let end = Self::SEQ_OFFSET + Self::SEQ_LENGTH;
buf[Self::SEQ_OFFSET..end].copy_from_slice(&seq_num.to_be_bytes());
let end = Self::MSG_COUNT_OFFSET + Self::MSG_COUNT_LENGTH;
buf[Self::MSG_COUNT_OFFSET..end].copy_from_slice(&msg_count.to_be_bytes());
Request(buf)
}
#[inline]
pub const fn as_bytes(&self) -> &[u8] {
&self.0
}
const SESSION_OFFSET: usize = 0;
const SESSION_LENGTH: usize = 10;
const SEQ_OFFSET: usize = 10;
const SEQ_LENGTH: usize = 8;
const MSG_COUNT_OFFSET: usize = 18;
const MSG_COUNT_LENGTH: usize = 2;
}