use std::{fmt, hint, mem};
use bitvec::{field::BitField, prelude as bv};
use paste::paste;
use crate::type_alias::*;
macro_rules! impl_accessor {
(
Field = $field:ident,
Self = $SelfT:ty,
ActualT = $ActualT:ty,
lsb = $lsb:expr,
msb = $msb:expr,
setter = $setter:tt,
getter = $getter:tt) => {
#[inline(always)]
pub fn $setter(&mut self, val: $SelfT) {
self.bits[$lsb..=$msb].store_le::<$ActualT>(val as $ActualT);
}
#[inline(always)]
pub fn $getter(&self) -> $SelfT {
self.bits[$lsb..=$msb].load_le::<$ActualT>().into()
}
};
(
Field = $field:ident,
Self = $SelfT:ty,
ActualT = $ActualT:ty,
lsb = $lsb:expr,
msb = $msb:expr
) => {
paste! {
impl_accessor!(
Field = $field,
Self = $SelfT,
ActualT = $ActualT,
lsb = $lsb,
msb = $msb,
setter = [< set_ $field >],
getter = $field
);
}
};
(
Field = $field:ident,
Self = $SelfT:ty,
lsb = $lsb:expr,
msb = $msb:expr
) => {
paste! {
impl_accessor!(
Field = $field,
Self = $SelfT,
ActualT = $SelfT,
lsb = $lsb,
msb = $msb
);
}
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub(crate) enum PktType {
SmallReq = 0,
LargeReq = 1,
SmallResp = 2,
LargeResp = 3,
}
impl From<u8> for PktType {
fn from(val: u8) -> Self {
match val {
0 => Self::SmallReq,
1 => Self::LargeReq,
2 => Self::SmallResp,
3 => Self::LargeResp,
_ => unsafe { hint::unreachable_unchecked() },
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub(crate) struct PacketHeader {
bits: bv::BitArr!(for 128),
}
impl PacketHeader {
impl_accessor!(Field = req_type, Self = ReqType, lsb = 0, msb = 7);
impl_accessor!(Field = data_len, Self = u32, lsb = 8, msb = 31);
impl_accessor!(Field = dst_sess_id, Self = SessId, lsb = 32, msb = 63);
impl_accessor!(Field = req_idx, Self = ReqIdx, lsb = 64, msb = 125);
impl_accessor!(Field = pkt_type, Self = PktType, ActualT = u8, lsb = 126, msb = 127);
pub fn new(
req_type: ReqType,
data_len: u32,
dst_sess_id: SessId,
req_idx: ReqIdx,
pkt_type: PktType,
) -> Self {
let mut this = Self::default();
this.set_req_type(req_type);
this.set_data_len(data_len);
this.set_dst_sess_id(dst_sess_id);
this.set_req_idx(req_idx);
this.set_pkt_type(pkt_type);
this
}
}
impl fmt::Debug for PacketHeader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PacketHeader")
.field("dst_sess_id", &self.dst_sess_id())
.field("pkt_type", &self.pkt_type())
.field("req_type", &self.req_type())
.field("req_idx", &self.req_idx())
.field("len", &self.data_len())
.finish()
}
}
impl Default for PacketHeader {
fn default() -> Self {
Self {
bits: bv::bitarr![0u8; mem::size_of::<PacketHeader>() * 8],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn header_layout() {
assert_eq!(mem::size_of::<PacketHeader>(), 16);
assert_eq!(mem::align_of::<PacketHeader>(), 8);
}
}