use crate::header::MessageHeader;
pub trait SbeEncoder: Sized {
const TEMPLATE_ID: u16;
const SCHEMA_ID: u16;
const SCHEMA_VERSION: u16;
const BLOCK_LENGTH: u16;
fn wrap(buffer: &mut [u8], offset: usize) -> Self;
fn encoded_length(&self) -> usize;
#[must_use]
fn create_header() -> MessageHeader {
MessageHeader {
block_length: Self::BLOCK_LENGTH,
template_id: Self::TEMPLATE_ID,
schema_id: Self::SCHEMA_ID,
version: Self::SCHEMA_VERSION,
}
}
}
#[derive(Debug)]
pub struct EncoderBuffer<'a> {
buffer: &'a mut [u8],
offset: usize,
position: usize,
}
impl<'a> EncoderBuffer<'a> {
#[must_use]
pub fn new(buffer: &'a mut [u8], offset: usize) -> Self {
Self {
buffer,
offset,
position: offset,
}
}
#[must_use]
pub fn buffer(&self) -> &[u8] {
self.buffer
}
pub fn buffer_mut(&mut self) -> &mut [u8] {
self.buffer
}
#[must_use]
pub const fn offset(&self) -> usize {
self.offset
}
#[must_use]
pub const fn position(&self) -> usize {
self.position
}
#[must_use]
pub const fn bytes_written(&self) -> usize {
self.position - self.offset
}
#[must_use]
pub fn remaining(&self) -> usize {
self.buffer.len() - self.position
}
pub fn advance(&mut self, count: usize) {
self.position += count;
}
pub fn set_position(&mut self, pos: usize) {
self.position = pos;
}
pub fn write_u8(&mut self, value: u8) {
self.buffer[self.position] = value;
self.position += 1;
}
pub fn write_u16_le(&mut self, value: u16) {
let bytes = value.to_le_bytes();
self.buffer[self.position..self.position + 2].copy_from_slice(&bytes);
self.position += 2;
}
pub fn write_u32_le(&mut self, value: u32) {
let bytes = value.to_le_bytes();
self.buffer[self.position..self.position + 4].copy_from_slice(&bytes);
self.position += 4;
}
pub fn write_u64_le(&mut self, value: u64) {
let bytes = value.to_le_bytes();
self.buffer[self.position..self.position + 8].copy_from_slice(&bytes);
self.position += 8;
}
pub fn write_bytes(&mut self, data: &[u8]) {
self.buffer[self.position..self.position + data.len()].copy_from_slice(data);
self.position += data.len();
}
pub fn write_zeros(&mut self, count: usize) {
self.buffer[self.position..self.position + count].fill(0);
self.position += count;
}
}
pub trait GroupEncoder {
type Entry<'a>
where
Self: 'a;
fn count(&self) -> u16;
fn next_entry(&mut self) -> Option<Self::Entry<'_>>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encoder_buffer_basic() {
let mut buf = [0u8; 64];
let mut encoder = EncoderBuffer::new(&mut buf, 0);
assert_eq!(encoder.offset(), 0);
assert_eq!(encoder.position(), 0);
assert_eq!(encoder.bytes_written(), 0);
assert_eq!(encoder.remaining(), 64);
encoder.write_u8(0xFF);
assert_eq!(encoder.position(), 1);
assert_eq!(encoder.bytes_written(), 1);
encoder.write_u16_le(0x1234);
assert_eq!(encoder.position(), 3);
encoder.write_u32_le(0xDEADBEEF);
assert_eq!(encoder.position(), 7);
encoder.write_u64_le(0x123456789ABCDEF0);
assert_eq!(encoder.position(), 15);
}
#[test]
fn test_encoder_buffer_with_offset() {
let mut buf = [0u8; 64];
let mut encoder = EncoderBuffer::new(&mut buf, 8);
assert_eq!(encoder.offset(), 8);
assert_eq!(encoder.position(), 8);
assert_eq!(encoder.bytes_written(), 0);
encoder.write_u32_le(0x12345678);
assert_eq!(encoder.position(), 12);
assert_eq!(encoder.bytes_written(), 4);
assert_eq!(buf[8], 0x78);
assert_eq!(buf[9], 0x56);
assert_eq!(buf[10], 0x34);
assert_eq!(buf[11], 0x12);
}
#[test]
fn test_encoder_buffer_write_bytes() {
let mut buf = [0u8; 64];
let mut encoder = EncoderBuffer::new(&mut buf, 0);
encoder.write_bytes(b"Hello");
assert_eq!(encoder.position(), 5);
assert_eq!(&buf[0..5], b"Hello");
}
#[test]
fn test_encoder_buffer_write_zeros() {
let mut buf = [0xFFu8; 64];
let mut encoder = EncoderBuffer::new(&mut buf, 0);
encoder.write_zeros(8);
assert_eq!(encoder.position(), 8);
assert!(buf[0..8].iter().all(|&b| b == 0));
assert_eq!(buf[8], 0xFF);
}
#[test]
fn test_encoder_buffer_advance() {
let mut buf = [0u8; 64];
let mut encoder = EncoderBuffer::new(&mut buf, 0);
encoder.advance(10);
assert_eq!(encoder.position(), 10);
assert_eq!(encoder.bytes_written(), 10);
}
#[test]
fn test_encoder_buffer_set_position() {
let mut buf = [0u8; 64];
let mut encoder = EncoderBuffer::new(&mut buf, 0);
encoder.write_u32_le(0x12345678);
assert_eq!(encoder.position(), 4);
encoder.set_position(20);
assert_eq!(encoder.position(), 20);
}
#[test]
fn test_encoder_buffer_buffer_access() {
let mut buf = [0u8; 64];
let mut encoder = EncoderBuffer::new(&mut buf, 0);
encoder.write_u8(0xAB);
assert_eq!(encoder.buffer()[0], 0xAB);
encoder.buffer_mut()[1] = 0xCD;
assert_eq!(encoder.buffer()[1], 0xCD);
}
#[test]
fn test_encoder_buffer_debug() {
let mut buf = [0u8; 64];
let encoder = EncoderBuffer::new(&mut buf, 0);
let debug_str = format!("{:?}", encoder);
assert!(debug_str.contains("EncoderBuffer"));
}
struct TestEncoder {
offset: usize,
len: usize,
}
impl SbeEncoder for TestEncoder {
const TEMPLATE_ID: u16 = 1;
const SCHEMA_ID: u16 = 100;
const SCHEMA_VERSION: u16 = 1;
const BLOCK_LENGTH: u16 = 16;
fn wrap(_buffer: &mut [u8], offset: usize) -> TestEncoder {
TestEncoder {
offset,
len: MessageHeader::ENCODED_LENGTH + Self::BLOCK_LENGTH as usize,
}
}
fn encoded_length(&self) -> usize {
self.len
}
}
#[test]
fn test_sbe_encoder_create_header() {
let header = TestEncoder::create_header();
let block_length = header.block_length;
let template_id = header.template_id;
let schema_id = header.schema_id;
let version = header.version;
assert_eq!(block_length, 16);
assert_eq!(template_id, 1);
assert_eq!(schema_id, 100);
assert_eq!(version, 1);
}
#[test]
fn test_sbe_encoder_wrap() {
let mut buf = [0u8; 64];
let encoder = TestEncoder::wrap(&mut buf, 0);
assert_eq!(encoder.offset, 0);
assert_eq!(encoder.encoded_length(), 24); }
}