use crate::error::{SbeError, SbeResult};
use simd_aligned::{VecSimd, arch::u8x16};
use smallvec::SmallVec;
use zerocopy::{FromBytes, IntoBytes, LittleEndian, U16, U32, U64};
pub const MAX_MESSAGE_SIZE: usize = 65536;
pub const DEFAULT_BUFFER_CAPACITY: usize = 1024;
pub const SBE_HEADER_SIZE: usize = 8;
pub struct SbeBuffer {
data: VecSimd<u8x16>,
position: usize,
capacity: usize,
}
impl SbeBuffer {
pub fn new() -> Self {
Self::with_capacity(DEFAULT_BUFFER_CAPACITY)
}
pub fn with_capacity(capacity: usize) -> Self {
let aligned_capacity = (capacity + 15) & !15; Self {
data: VecSimd::with(0u8, aligned_capacity),
position: 0,
capacity: aligned_capacity,
}
}
pub fn from_slice(slice: &[u8]) -> SbeResult<Self> {
if slice.len() > MAX_MESSAGE_SIZE {
return Err(SbeError::MessageTooLarge {
length: slice.len(),
max: MAX_MESSAGE_SIZE,
});
}
let aligned_capacity = (slice.len() + 15) & !15;
let mut buffer = Self::with_capacity(aligned_capacity);
buffer.data.flat_mut()[..slice.len()].copy_from_slice(slice);
buffer.position = slice.len();
Ok(buffer)
}
pub fn len(&self) -> usize {
self.position
}
pub fn is_empty(&self) -> bool {
self.position == 0
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn remaining(&self) -> usize {
self.capacity - self.position
}
pub fn clear(&mut self) {
self.position = 0;
}
pub fn as_slice(&self) -> &[u8] {
&self.data.flat()[..self.position]
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.data.flat_mut()[..self.position]
}
pub fn reserve(&mut self, additional: usize) -> SbeResult<()> {
let new_capacity = self
.position
.checked_add(additional)
.ok_or(SbeError::IntegerOverflow)?;
if new_capacity > self.capacity {
if new_capacity > MAX_MESSAGE_SIZE {
return Err(SbeError::MessageTooLarge {
length: new_capacity,
max: MAX_MESSAGE_SIZE,
});
}
let aligned_capacity = (new_capacity + 15) & !15;
let mut new_data = VecSimd::with(0u8, aligned_capacity);
new_data.flat_mut()[..self.position]
.copy_from_slice(&self.data.flat()[..self.position]);
self.data = new_data;
self.capacity = aligned_capacity;
}
Ok(())
}
pub fn write_bytes(&mut self, bytes: &[u8]) -> SbeResult<()> {
self.reserve(bytes.len())?;
self.data.flat_mut()[self.position..self.position + bytes.len()].copy_from_slice(bytes);
self.position += bytes.len();
Ok(())
}
pub fn write_at_offset<T>(&mut self, offset: usize, value: T) -> SbeResult<()>
where
T: IntoBytes + zerocopy::Immutable,
{
let bytes = value.as_bytes();
let end_offset = offset
.checked_add(bytes.len())
.ok_or(SbeError::IntegerOverflow)?;
if end_offset > self.position {
return Err(SbeError::FieldOffsetOutOfBounds {
offset,
length: self.position,
});
}
self.data.flat_mut()[offset..end_offset].copy_from_slice(bytes);
Ok(())
}
pub fn read_at_offset<T>(&self, offset: usize) -> SbeResult<T>
where
T: FromBytes + Copy,
{
let size = std::mem::size_of::<T>();
let end_offset = offset.checked_add(size).ok_or(SbeError::IntegerOverflow)?;
if end_offset > self.position {
return Err(SbeError::FieldOffsetOutOfBounds {
offset,
length: self.position,
});
}
T::read_from_bytes(&self.data.flat()[offset..end_offset]).map_err(|_| {
SbeError::FieldOffsetOutOfBounds {
offset,
length: self.position,
}
})
}
}
impl Default for SbeBuffer {
fn default() -> Self {
Self::new()
}
}
pub struct SbeReader<'a> {
pub(crate) data: &'a [u8],
position: usize,
}
impl<'a> SbeReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data, position: 0 }
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.position >= self.data.len()
}
pub fn position(&self) -> usize {
self.position
}
pub fn set_position(&mut self, position: usize) -> SbeResult<()> {
if position > self.data.len() {
return Err(SbeError::FieldOffsetOutOfBounds {
offset: position,
length: self.data.len(),
});
}
self.position = position;
Ok(())
}
pub fn read_at<T>(&self, offset: usize) -> SbeResult<T>
where
T: FromBytes + Copy,
{
let size = std::mem::size_of::<T>();
let end_offset = offset.checked_add(size).ok_or(SbeError::IntegerOverflow)?;
if end_offset > self.data.len() {
return Err(SbeError::FieldOffsetOutOfBounds {
offset,
length: self.data.len(),
});
}
T::read_from_bytes(&self.data[offset..end_offset]).map_err(|_| {
SbeError::FieldOffsetOutOfBounds {
offset,
length: self.data.len(),
}
})
}
pub fn read_bytes_at(&self, offset: usize, length: usize) -> SbeResult<&'a [u8]> {
let end_offset = offset
.checked_add(length)
.ok_or(SbeError::IntegerOverflow)?;
if end_offset > self.data.len() {
return Err(SbeError::FieldOffsetOutOfBounds {
offset,
length: self.data.len(),
});
}
Ok(&self.data[offset..end_offset])
}
pub fn read_u16(&self, offset: usize) -> SbeResult<u16> {
let value: U16<LittleEndian> = self.read_at(offset)?;
Ok(value.get())
}
pub fn read_u32(&self, offset: usize) -> SbeResult<u32> {
let value: U32<LittleEndian> = self.read_at(offset)?;
Ok(value.get())
}
pub fn read_u64(&self, offset: usize) -> SbeResult<u64> {
let value: U64<LittleEndian> = self.read_at(offset)?;
Ok(value.get())
}
pub fn read_u8(&self, offset: usize) -> SbeResult<u8> {
self.read_at(offset)
}
pub fn read_f32(&self, offset: usize) -> SbeResult<f32> {
let bytes = self.read_at::<[u8; 4]>(offset)?;
Ok(f32::from_le_bytes(bytes))
}
pub fn read_string_at(&self, offset: usize, length: usize) -> SbeResult<&'a str> {
let bytes = self.read_bytes_at(offset, length)?;
let string_bytes = if let Some(null_pos) = bytes.iter().position(|&b| b == 0) {
&bytes[..null_pos]
} else {
bytes
};
std::str::from_utf8(string_bytes).map_err(|_| SbeError::InvalidUtf8String)
}
}
pub type SbeSmallVec<T> = SmallVec<[T; 8]>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_buffer_creation() {
let buffer = SbeBuffer::new();
assert_eq!(buffer.len(), 0);
assert!(!buffer.is_empty() || buffer.is_empty());
assert!(buffer.capacity() >= DEFAULT_BUFFER_CAPACITY);
}
#[test]
fn test_buffer_write_read() {
let mut buffer = SbeBuffer::new();
let data = b"Hello, SBE!";
buffer.write_bytes(data).unwrap();
assert_eq!(buffer.len(), data.len());
assert_eq!(buffer.as_slice(), data);
}
#[test]
fn test_reader_operations() {
let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let reader = SbeReader::new(&data);
assert_eq!(reader.read_u16(0).unwrap(), 0x0201);
assert_eq!(reader.read_u16(2).unwrap(), 0x0403);
assert_eq!(reader.read_u32(0).unwrap(), 0x04030201);
assert!(reader.read_u32(6).is_err());
}
#[test]
fn test_alignment() {
let buffer = SbeBuffer::with_capacity(100);
assert_eq!(buffer.capacity() % 16, 0);
}
}