use std::str;
use super::{MAX_GROUP_SIZE, SbeDecodeError};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GroupSizeEncoding {
pub block_length: u16,
pub num_in_group: u32,
}
impl GroupSizeEncoding {
pub const ENCODED_LENGTH: usize = 6;
pub fn decode(buf: &[u8]) -> Result<Self, SbeDecodeError> {
if buf.len() < Self::ENCODED_LENGTH {
return Err(SbeDecodeError::BufferTooShort {
expected: Self::ENCODED_LENGTH,
actual: buf.len(),
});
}
let num_in_group = u32::from_le_bytes([buf[2], buf[3], buf[4], buf[5]]);
if num_in_group > MAX_GROUP_SIZE {
return Err(SbeDecodeError::GroupSizeTooLarge {
count: num_in_group,
max: MAX_GROUP_SIZE,
});
}
Ok(Self {
block_length: u16::from_le_bytes([buf[0], buf[1]]),
num_in_group,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GroupSize16Encoding {
pub block_length: u16,
pub num_in_group: u16,
}
impl GroupSize16Encoding {
pub const ENCODED_LENGTH: usize = 4;
pub fn decode(buf: &[u8]) -> Result<Self, SbeDecodeError> {
if buf.len() < Self::ENCODED_LENGTH {
return Err(SbeDecodeError::BufferTooShort {
expected: Self::ENCODED_LENGTH,
actual: buf.len(),
});
}
let num_in_group = u16::from_le_bytes([buf[2], buf[3]]);
if u32::from(num_in_group) > MAX_GROUP_SIZE {
return Err(SbeDecodeError::GroupSizeTooLarge {
count: u32::from(num_in_group),
max: MAX_GROUP_SIZE,
});
}
Ok(Self {
block_length: u16::from_le_bytes([buf[0], buf[1]]),
num_in_group,
})
}
}
pub fn decode_var_string8(buf: &[u8]) -> Result<(&str, usize), SbeDecodeError> {
if buf.is_empty() {
return Err(SbeDecodeError::BufferTooShort {
expected: 1,
actual: 0,
});
}
let len = usize::from(buf[0]);
let total_len = 1 + len;
if buf.len() < total_len {
return Err(SbeDecodeError::BufferTooShort {
expected: total_len,
actual: buf.len(),
});
}
let s = str::from_utf8(&buf[1..total_len]).map_err(|_| SbeDecodeError::InvalidUtf8)?;
Ok((s, total_len))
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
fn test_group_size_decode_too_short() {
let err = GroupSizeEncoding::decode(&[0, 0, 0]).unwrap_err();
assert!(matches!(err, SbeDecodeError::BufferTooShort { .. }));
}
#[rstest]
fn test_group_size_decode_too_large() {
let mut buf = [0u8; GroupSizeEncoding::ENCODED_LENGTH];
buf[2..6].copy_from_slice(&(MAX_GROUP_SIZE + 1).to_le_bytes());
let err = GroupSizeEncoding::decode(&buf).unwrap_err();
assert!(matches!(err, SbeDecodeError::GroupSizeTooLarge { .. }));
}
#[rstest]
fn test_group_size_16_decode_too_large() {
let mut buf = [0u8; GroupSize16Encoding::ENCODED_LENGTH];
buf[2..4].copy_from_slice(&(MAX_GROUP_SIZE as u16 + 1).to_le_bytes());
let err = GroupSize16Encoding::decode(&buf).unwrap_err();
assert!(matches!(err, SbeDecodeError::GroupSizeTooLarge { .. }));
}
#[rstest]
fn test_decode_var_string8_valid() {
let buf = [5u8, b'H', b'E', b'L', b'L', b'O'];
let (s, consumed) = decode_var_string8(&buf).unwrap();
assert_eq!(s, "HELLO");
assert_eq!(consumed, 6);
}
#[rstest]
fn test_decode_var_string8_invalid_utf8() {
let buf = [2u8, 0xFF, 0xFF];
let err = decode_var_string8(&buf).unwrap_err();
assert_eq!(err, SbeDecodeError::InvalidUtf8);
}
}