use crate::buffer::{ReadBuffer, WriteBuffer};
#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct MessageHeader {
pub block_length: u16,
pub template_id: u16,
pub schema_id: u16,
pub version: u16,
}
impl MessageHeader {
pub const ENCODED_LENGTH: usize = 8;
#[must_use]
pub const fn new(block_length: u16, template_id: u16, schema_id: u16, version: u16) -> Self {
Self {
block_length,
template_id,
schema_id,
version,
}
}
#[inline(always)]
#[must_use]
pub fn wrap<B: ReadBuffer + ?Sized>(buffer: &B, offset: usize) -> Self {
Self {
block_length: buffer.get_u16_le(offset),
template_id: buffer.get_u16_le(offset + 2),
schema_id: buffer.get_u16_le(offset + 4),
version: buffer.get_u16_le(offset + 6),
}
}
#[inline(always)]
pub fn encode<B: WriteBuffer + ?Sized>(&self, buffer: &mut B, offset: usize) {
buffer.put_u16_le(offset, self.block_length);
buffer.put_u16_le(offset + 2, self.template_id);
buffer.put_u16_le(offset + 4, self.schema_id);
buffer.put_u16_le(offset + 6, self.version);
}
#[must_use]
pub const fn message_size(&self) -> usize {
Self::ENCODED_LENGTH + self.block_length as usize
}
}
#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct GroupHeader {
pub block_length: u16,
pub num_in_group: u16,
}
impl GroupHeader {
pub const ENCODED_LENGTH: usize = 4;
#[must_use]
pub const fn new(block_length: u16, num_in_group: u16) -> Self {
Self {
block_length,
num_in_group,
}
}
#[inline(always)]
#[must_use]
pub fn wrap<B: ReadBuffer + ?Sized>(buffer: &B, offset: usize) -> Self {
Self {
block_length: buffer.get_u16_le(offset),
num_in_group: buffer.get_u16_le(offset + 2),
}
}
#[inline(always)]
pub fn encode<B: WriteBuffer + ?Sized>(&self, buffer: &mut B, offset: usize) {
buffer.put_u16_le(offset, self.block_length);
buffer.put_u16_le(offset + 2, self.num_in_group);
}
#[must_use]
pub const fn group_size(&self) -> usize {
Self::ENCODED_LENGTH + (self.block_length as usize * self.num_in_group as usize)
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.num_in_group == 0
}
}
#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct VarDataHeader {
pub length: u16,
}
impl VarDataHeader {
pub const ENCODED_LENGTH: usize = 2;
#[must_use]
pub const fn new(length: u16) -> Self {
Self { length }
}
#[inline(always)]
#[must_use]
pub fn wrap<B: ReadBuffer + ?Sized>(buffer: &B, offset: usize) -> Self {
Self {
length: buffer.get_u16_le(offset),
}
}
#[inline(always)]
pub fn encode<B: WriteBuffer + ?Sized>(&self, buffer: &mut B, offset: usize) {
buffer.put_u16_le(offset, self.length);
}
#[must_use]
pub const fn total_size(&self) -> usize {
Self::ENCODED_LENGTH + self.length as usize
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.length == 0
}
}
#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VarDataHeader8 {
pub length: u8,
}
impl VarDataHeader8 {
pub const ENCODED_LENGTH: usize = 1;
#[must_use]
pub const fn new(length: u8) -> Self {
Self { length }
}
#[inline(always)]
#[must_use]
pub fn wrap<B: ReadBuffer + ?Sized>(buffer: &B, offset: usize) -> Self {
Self {
length: buffer.get_u8(offset),
}
}
#[inline(always)]
pub fn encode<B: WriteBuffer + ?Sized>(&self, buffer: &mut B, offset: usize) {
buffer.put_u8(offset, self.length);
}
}
#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VarDataHeader32 {
pub length: u32,
}
impl VarDataHeader32 {
pub const ENCODED_LENGTH: usize = 4;
#[must_use]
pub const fn new(length: u32) -> Self {
Self { length }
}
#[inline(always)]
#[must_use]
pub fn wrap<B: ReadBuffer + ?Sized>(buffer: &B, offset: usize) -> Self {
Self {
length: buffer.get_u32_le(offset),
}
}
#[inline(always)]
pub fn encode<B: WriteBuffer + ?Sized>(&self, buffer: &mut B, offset: usize) {
buffer.put_u32_le(offset, self.length);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::buffer::AlignedBuffer;
#[test]
fn test_message_header_encode_decode() {
let mut buf: AlignedBuffer<16> = AlignedBuffer::new();
let header = MessageHeader::new(64, 1, 100, 1);
header.encode(&mut buf, 0);
let decoded = MessageHeader::wrap(&buf, 0);
assert_eq!(header, decoded);
assert_eq!({ decoded.block_length }, 64);
assert_eq!({ decoded.template_id }, 1);
assert_eq!({ decoded.schema_id }, 100);
assert_eq!({ decoded.version }, 1);
}
#[test]
fn test_message_header_size() {
assert_eq!(MessageHeader::ENCODED_LENGTH, 8);
let header = MessageHeader::new(64, 1, 100, 1);
assert_eq!(header.message_size(), 72);
}
#[test]
fn test_group_header_encode_decode() {
let mut buf: AlignedBuffer<16> = AlignedBuffer::new();
let header = GroupHeader::new(32, 5);
header.encode(&mut buf, 0);
let decoded = GroupHeader::wrap(&buf, 0);
assert_eq!(header, decoded);
assert_eq!({ decoded.block_length }, 32);
assert_eq!({ decoded.num_in_group }, 5);
}
#[test]
fn test_group_header_size() {
assert_eq!(GroupHeader::ENCODED_LENGTH, 4);
let header = GroupHeader::new(32, 5);
assert_eq!(header.group_size(), 4 + 32 * 5);
assert!(!header.is_empty());
let empty = GroupHeader::new(32, 0);
assert!(empty.is_empty());
}
#[test]
fn test_var_data_header_encode_decode() {
let mut buf: AlignedBuffer<16> = AlignedBuffer::new();
let header = VarDataHeader::new(256);
header.encode(&mut buf, 0);
let decoded = VarDataHeader::wrap(&buf, 0);
assert_eq!(header, decoded);
assert_eq!({ decoded.length }, 256);
assert_eq!(decoded.total_size(), 258);
}
#[test]
fn test_var_data_header8() {
let mut buf: AlignedBuffer<16> = AlignedBuffer::new();
let header = VarDataHeader8::new(100);
header.encode(&mut buf, 0);
let decoded = VarDataHeader8::wrap(&buf, 0);
assert_eq!(header, decoded);
assert_eq!(VarDataHeader8::ENCODED_LENGTH, 1);
}
#[test]
fn test_var_data_header32() {
let mut buf: AlignedBuffer<16> = AlignedBuffer::new();
let header = VarDataHeader32::new(1_000_000);
header.encode(&mut buf, 0);
let decoded = VarDataHeader32::wrap(&buf, 0);
assert_eq!(header, decoded);
assert_eq!(VarDataHeader32::ENCODED_LENGTH, 4);
}
#[test]
fn test_header_wire_format() {
let mut buf: AlignedBuffer<16> = AlignedBuffer::new();
let header = MessageHeader::new(0x0102, 0x0304, 0x0506, 0x0708);
header.encode(&mut buf, 0);
assert_eq!(buf.get_u8(0), 0x02); assert_eq!(buf.get_u8(1), 0x01); assert_eq!(buf.get_u8(2), 0x04); assert_eq!(buf.get_u8(3), 0x03); assert_eq!(buf.get_u8(4), 0x06); assert_eq!(buf.get_u8(5), 0x05); assert_eq!(buf.get_u8(6), 0x08); assert_eq!(buf.get_u8(7), 0x07); }
}