use super::{PacketBytes, Result};
use bytes::Bytes;
pub trait Packet<B>: Sized
where B: PacketBytes {type Header: PacketHeader;
fn header(&self) -> &Self::Header;
fn header_mut(&mut self) -> &mut Self::Header;
fn empty() -> Self;
fn from_bytes_and_header(bytes: B, header: Self::Header) -> Result<Self>;
fn into_bytes(self) -> B;
}
pub trait PacketHeader: Clone + Sized {
const LEN: u32;
fn from_bytes(bytes: Bytes) -> Result<Self>;
fn body_len(&self) -> u32;
fn flags(&self) -> &Flags;
fn set_flags(&mut self, flags: Flags);
fn id(&self) -> u32;
fn set_id(&mut self, id: u32);
}
macro_rules! kind {
($($variant:ident = $val:expr),*) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Kind {
$($variant),*,
Unknown
}
impl Kind {
fn from_num(num: u8) -> Self {
debug_assert!(num <= MAX_KIND);
match num {
$($val => Self::$variant),*,
_ => Self::Unknown
}
}
fn as_num(&self) -> u8 {
match self {
$(Self::$variant => $val),*,
Self::Unknown => MAX_KIND
}
}
#[cfg_attr(not(feature = "connection"), allow(dead_code))]
pub(crate) fn to_str(&self) -> &'static str {
match self {
$(Self::$variant => stringify!($variant)),*,
Self::Unknown => "Unknown"
}
}
}
}
}
kind!{
Request = 1,
Response = 2,
NoResponse = 3,
Stream = 4,
RequestReceiver = 5,
RequestSender = 6,
StreamClosed = 7,
Close = 8,
Ping = 9,
MalformedRequest = 10
}
const KIND_OFFSET: u8 = 4;
const MAX_KIND: u8 = u8::MAX >> KIND_OFFSET;
const KIND_MASK: u8 = 0b1111 << KIND_OFFSET;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Flags {
inner: u8
}
impl Flags {
#[cfg_attr(not(feature = "connection"), allow(dead_code))]
pub(crate) fn new(kind: Kind) -> Self {
let mut this = Self { inner: 0 };
this.set_kind(kind);
this
}
pub fn empty() -> Self {
Self { inner: 0 }
}
pub fn from_u8(num: u8) -> Result<Self> {
Ok(Self { inner: num })
}
pub(crate) fn kind(&self) -> Kind {
let num = self.inner >> KIND_OFFSET;
Kind::from_num(num)
}
pub(crate) fn set_kind(&mut self, kind: Kind) {
let num = kind.as_num();
debug_assert!(num < MAX_KIND);
self.inner &= !KIND_MASK;
self.inner |= num << KIND_OFFSET;
}
pub fn as_u8(&self) -> u8 {
self.inner
}
pub fn is_request(&self) -> bool {
matches!(self.kind(), Kind::Request)
}
pub fn is_response(&self) -> bool {
matches!(self.kind(), Kind::Response)
}
}