use super::format::{HEADER_LEN, MAGIC, to_u64, to_usize};
use crate::error::SearchError;
pub(super) struct Encoder {
pub(super) data: Vec<u8>,
}
impl Encoder {
pub(super) fn with_header() -> Result<Self, SearchError> {
let mut data = Vec::new();
data.try_reserve_exact(HEADER_LEN)
.map_err(|_| SearchError::AllocationFailed)?;
data.extend_from_slice(MAGIC);
data.resize(HEADER_LEN, 0);
Ok(Self { data })
}
fn reserve(&mut self, additional: usize) -> Result<(), SearchError> {
self.data
.try_reserve(additional)
.map_err(|_| SearchError::AllocationFailed)
}
pub(super) fn bytes(&mut self, value: &[u8]) -> Result<(), SearchError> {
self.reserve(value.len())?;
self.data.extend_from_slice(value);
Ok(())
}
pub(super) fn u8(&mut self, value: u8) -> Result<(), SearchError> {
self.reserve(1)?;
self.data.push(value);
Ok(())
}
pub(super) fn u32(&mut self, value: u32) -> Result<(), SearchError> {
self.bytes(&value.to_le_bytes())
}
pub(super) fn u64(&mut self, value: u64) -> Result<(), SearchError> {
self.bytes(&value.to_le_bytes())
}
pub(super) fn f32s(&mut self, values: &[f32]) -> Result<(), SearchError> {
self.reserve(
values
.len()
.checked_mul(std::mem::size_of::<f32>())
.ok_or(SearchError::CapacityOverflow)?,
)?;
for value in values {
self.data.extend_from_slice(&value.to_bits().to_le_bytes());
}
Ok(())
}
pub(super) fn length_prefixed(&mut self, value: &[u8]) -> Result<(), SearchError> {
self.u64(to_u64(value.len())?)?;
self.bytes(value)
}
}
pub(super) struct Decoder<'a> {
bytes: &'a [u8],
cursor: usize,
}
impl<'a> Decoder<'a> {
pub(super) const fn new(bytes: &'a [u8], cursor: usize) -> Self {
Self { bytes, cursor }
}
pub(super) fn take(&mut self, length: usize) -> Result<&'a [u8], SearchError> {
let end = self
.cursor
.checked_add(length)
.ok_or(SearchError::CapacityOverflow)?;
let value = self
.bytes
.get(self.cursor..end)
.ok_or(SearchError::CorruptSnapshot("bundle payload is truncated"))?;
self.cursor = end;
Ok(value)
}
pub(super) fn u8(&mut self) -> Result<u8, SearchError> {
Ok(self.take(1)?[0])
}
pub(super) fn u32(&mut self) -> Result<u32, SearchError> {
Ok(u32::from_le_bytes(
self.take(4)?
.try_into()
.expect("checked four-byte bundle value"),
))
}
pub(super) fn u64(&mut self) -> Result<u64, SearchError> {
Ok(u64::from_le_bytes(
self.take(8)?
.try_into()
.expect("checked eight-byte bundle value"),
))
}
pub(super) fn f32s(&mut self, length: usize) -> Result<Vec<f32>, SearchError> {
let byte_length = length
.checked_mul(std::mem::size_of::<f32>())
.ok_or(SearchError::CapacityOverflow)?;
let bytes = self.take(byte_length)?;
let mut values = Vec::new();
values
.try_reserve_exact(length)
.map_err(|_| SearchError::AllocationFailed)?;
values.extend(bytes.chunks_exact(4).map(|chunk| {
f32::from_bits(u32::from_le_bytes(
chunk.try_into().expect("four-byte f32 chunk"),
))
}));
Ok(values)
}
pub(super) fn length_prefixed(&mut self) -> Result<&'a [u8], SearchError> {
let length = to_usize(self.u64()?)?;
self.take(length)
}
pub(super) const fn is_finished(&self) -> bool {
self.cursor == self.bytes.len()
}
}