use crate::utils::{rv_u8, rv_u16, wv_u8, wv_u16};
pub struct Packet {
pub magic: u16, pub flag: u8,
pub len: u8,
}
pub const MAGIC: u16 = 0xC0DE;
pub const FLAG_OFFSET: usize = 2;
pub const LEN_OFFSET: usize = 3;
pub const FLAG_VALID: u8 = 0b0000_0001;
pub const FLAG_CONSUMED: u8 = 0b0000_0010;
pub const PACKET_HEADER_SIZE: usize = core::mem::size_of::<Packet>();
impl Packet {
pub const fn new(len: u8) -> Self {
Self {
magic: MAGIC,
flag: FLAG_VALID,
len,
}
}
pub unsafe fn try_from_raw_ptr(ptr: *const u8) -> Option<Self> {
let magic = unsafe { rv_u16(ptr, 0) };
if magic != MAGIC {
return None;
}
let flag = unsafe { rv_u8(ptr, FLAG_OFFSET) };
let len = unsafe { rv_u8(ptr, LEN_OFFSET) };
Some(Self { magic, flag, len })
}
pub unsafe fn read_payload(&mut self, base: *mut u8, payload: &mut [u8]) {
let src = unsafe { base.add(PACKET_HEADER_SIZE) };
for (offset, byte) in payload.iter_mut().take(self.len as usize).enumerate() {
*byte = unsafe { rv_u8(src, offset) };
}
}
pub unsafe fn write_to_raw_ptr(&self, ptr: *mut u8) {
unsafe { wv_u16(ptr, 0, self.magic) };
unsafe { wv_u8(ptr, FLAG_OFFSET, self.flag) };
unsafe { wv_u8(ptr, LEN_OFFSET, self.len) };
}
pub unsafe fn write_payload_to_raw_ptr(&self, ptr: *mut u8, payload: &[u8]) {
let dst = unsafe { ptr.add(PACKET_HEADER_SIZE) };
unsafe { core::ptr::copy_nonoverlapping(payload.as_ptr(), dst, self.len as usize) };
}
pub unsafe fn write_full_packet_to_raw_ptr(ptr: *mut u8, payload: &[u8]) {
let packet = Self::new(payload.len() as u8);
unsafe { packet.write_to_raw_ptr(ptr) };
unsafe { packet.write_payload_to_raw_ptr(ptr, payload) };
}
pub unsafe fn mark_as_consumed(&mut self, ptr: *mut u8) {
self.flag |= FLAG_CONSUMED;
unsafe { wv_u8(ptr, FLAG_OFFSET, self.flag) };
}
pub fn is_valid(&self) -> bool {
self.magic == MAGIC && (self.flag & FLAG_VALID != 0) && (self.flag & FLAG_CONSUMED == 0)
}
}