use bytes::{Bytes, BytesMut};
pub trait Framer {
fn get_frame_length(bytes: &BytesMut) -> Option<usize>;
#[inline(always)]
fn get_frame(bytes: &mut BytesMut) -> Option<Bytes> {
let frame_length = Self::get_frame_length(bytes)?;
if bytes.len() < frame_length {
None
} else {
let frame = bytes.split_to(frame_length);
Some(frame.freeze())
}
}
}
pub struct FixedSizeFramer<const FRAME_SIZE: usize>;
impl<const FRAME_SIZE: usize> Framer for FixedSizeFramer<FRAME_SIZE> {
#[inline(always)]
fn get_frame_length(bytes: &BytesMut) -> Option<usize> {
if bytes.len() < FRAME_SIZE {
None
} else {
Some(FRAME_SIZE)
}
}
}
pub struct PacketLengthU16Framer<const START_IDX: usize, const IS_BIG_ENDIAN: bool, const ADD_PACKET_LEN_TO_FRAME_SIZE: bool>;
impl<const START_IDX: usize, const IS_BIG_ENDIAN: bool, const ADD_PACKET_LEN_TO_FRAME_SIZE: bool> PacketLengthU16Framer<START_IDX, IS_BIG_ENDIAN, ADD_PACKET_LEN_TO_FRAME_SIZE> {
#[inline(always)]
pub fn packet_len(bytes: &BytesMut) -> Option<u16> {
const LEN: usize = std::mem::size_of::<u16>();
if bytes.len() < START_IDX + LEN {
return None;
}
let packet_length = {
let opt = bytes.get(START_IDX..LEN).map(|src| {
if IS_BIG_ENDIAN {
unsafe { u16::from_be_bytes(*(src as *const _ as *const [_; LEN])) }
} else {
unsafe { u16::from_le_bytes(*(src as *const _ as *const [_; LEN])) }
}
});
if let Some(len) = opt {
len
} else {
let mut buf = [0_u8; LEN];
let packet_length = &bytes[START_IDX..LEN];
buf[0] = packet_length[0];
buf[1] = packet_length[1];
if IS_BIG_ENDIAN {
u16::from_be_bytes(buf)
} else {
u16::from_le_bytes(buf)
}
}
};
Some(packet_length)
}
}
impl<const START_IDX: usize, const IS_BIG_ENDIAN: bool, const ADD_PACKET_LEN_TO_FRAME_SIZE: bool> Framer for PacketLengthU16Framer<START_IDX, IS_BIG_ENDIAN, ADD_PACKET_LEN_TO_FRAME_SIZE> {
#[inline(always)]
fn get_frame_length(bytes: &BytesMut) -> Option<usize> {
let packet_length = Self::packet_len(bytes)?;
let frame_length = {
if ADD_PACKET_LEN_TO_FRAME_SIZE {
packet_length as usize + START_IDX + std::mem::size_of::<u16>()
} else {
packet_length as usize
}
};
if bytes.len() < frame_length {
None
} else {
Some(frame_length)
}
}
}
#[cfg(test)]
mod test {
use bytes::{BufMut, BytesMut};
use log::info;
use crate::{core::framer::PacketLengthU16Framer, unittest::setup};
use super::{FixedSizeFramer, Framer};
#[test]
fn test_fixed_size_framer() {
setup::log::configure();
let mut buf = BytesMut::from(&b"12345"[..]);
let frame = FixedSizeFramer::<2>::get_frame(&mut buf).unwrap();
info!("frame: {:?}", frame);
assert_eq!(frame, &b"12"[..]);
let frame = FixedSizeFramer::<2>::get_frame(&mut buf).unwrap();
info!("frame: {:?}", frame);
assert_eq!(frame, &b"34"[..]);
let frame = FixedSizeFramer::<2>::get_frame(&mut buf);
info!("frame: {:?}", frame);
assert!(frame.is_none());
}
#[test]
fn test_packet_len_u16_framer() {
setup::log::configure();
const START: usize = 0;
const ADD_PACKET_LEN_TO_FRAME_SIZE: bool = true;
let test_lens = [0x0001_u16, 0x0100];
let frame_lens_big = [Some(3_usize), None];
let frame_lens_lit = [None, Some(3_usize)];
for (idx, expected_packet_len) in test_lens.into_iter().enumerate() {
info!("idx: ==== {:?} ==== BIG ENDIAN", idx);
let mut bytes = BytesMut::from(expected_packet_len.to_be_bytes().as_slice());
bytes.put_bytes(0, 1);
let actual_packet_len = PacketLengthU16Framer::<START, true, ADD_PACKET_LEN_TO_FRAME_SIZE>::packet_len(&mut bytes).unwrap();
info!("bytes: {:x?}", &bytes[..]);
info!("expected_packet_len: {:x?} {:?}", expected_packet_len.to_be_bytes(), expected_packet_len,);
info!("actual_packet_len: {:x?} {:?}", actual_packet_len.to_be_bytes(), actual_packet_len,);
assert_eq!(actual_packet_len, expected_packet_len);
let frame_len = PacketLengthU16Framer::<START, true, ADD_PACKET_LEN_TO_FRAME_SIZE>::get_frame_length(&mut bytes);
info!("frame_len: {:?}", frame_len);
assert_eq!(frame_len, frame_lens_big[idx]);
info!("idx: ==== {:?} ==== LIT ENDIAN", idx);
let actual_packet_len = PacketLengthU16Framer::<START, false, ADD_PACKET_LEN_TO_FRAME_SIZE>::packet_len(&mut bytes).unwrap();
let expected_packet_len = u16::from_be_bytes(expected_packet_len.to_le_bytes()); info!("bytes: {:x?}", &bytes[..]);
info!("expected_packet_len: {:x?} {:?}", expected_packet_len.to_be_bytes(), expected_packet_len,);
info!("actual_packet_len: {:x?} {:?}", actual_packet_len.to_be_bytes(), actual_packet_len,);
assert_eq!(actual_packet_len, expected_packet_len);
let frame_len = PacketLengthU16Framer::<START, false, ADD_PACKET_LEN_TO_FRAME_SIZE>::get_frame_length(&mut bytes);
info!("frame_len: {:?}", frame_len);
assert_eq!(frame_len, frame_lens_lit[idx]);
}
}
}