use snafu::ensure;
use crate::{codec::UnsupportedDataFormatSnafu, stream::Reads};
use super::{
encode::Encodable, CodecError, DataFormat, DataHeader, FormatMetadata,
UnexpectedDataFormatSnafu,
};
pub const TEMP_BUFFER_SIZE: usize = 1024;
pub trait Decodable: Encodable {
fn decode(
&mut self,
reader: &mut (impl ReadsDecodable + ?Sized),
header: Option<DataHeader>,
) -> Result<(), CodecError>;
#[inline(always)]
fn ensure_header(
header: Option<DataHeader>,
supported_ordinals: &[FormatMetadata],
) -> Result<DataHeader, CodecError> {
let header = header.ok_or_else(|| {
UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: header,
}
.build()
})?;
ensure!(
supported_ordinals.contains(&header.format.ordinal),
UnsupportedDataFormatSnafu {
ordinal: header.format.ordinal
}
);
Ok(header)
}
#[inline(always)]
fn ensure_no_header(header: Option<DataHeader>) -> Result<(), CodecError> {
ensure!(
header.is_none(),
UnexpectedDataFormatSnafu {
expected: Self::FORMAT,
actual: header,
}
);
Ok(())
}
}
pub trait ReadsDecodable: Reads {
fn read_data<T: Decodable + Default>(&mut self) -> Result<T, CodecError> {
let mut default = T::default();
self.read_data_into(&mut default)?;
Ok(default)
}
fn read_data_into<T: Decodable>(&mut self, data: &mut T) -> Result<(), CodecError> {
if T::FORMAT.is_structured() {
let header = self.read_data()?;
data.decode(self, Some(header))?;
} else {
data.decode(self, None)?;
}
Ok(())
}
fn skip_blob(&mut self, length: usize) -> Result<(), CodecError> {
let mut skipped = 0;
let mut buf = [0; TEMP_BUFFER_SIZE];
while skipped < length {
let remaining = length - skipped;
if remaining < TEMP_BUFFER_SIZE {
skipped += self.read(&mut buf[..remaining])?;
} else {
skipped += self.read(&mut buf)?;
}
}
Ok(())
}
fn skip_data(&mut self) -> Result<usize, CodecError> {
let mut read = 0;
let header: DataHeader = self.read_data()?;
read += DataHeader::FORMAT.as_data_format().blob_size as usize;
let data_format = header.format;
for _ in 0..header.count {
read += self.skip_data_with_format(data_format)?;
}
Ok(read)
}
fn skip_data_with_format(&mut self, format: DataFormat) -> Result<usize, CodecError> {
let mut read = 0;
self.skip_blob(format.blob_size as usize)?;
read += format.blob_size as usize;
for _ in 0..format.data_fields {
read += self.skip_data()?;
}
Ok(read)
}
}
impl<T: Reads + ?Sized> ReadsDecodable for T {}
#[cfg(test)]
mod tests {
use super::*;
use crate::{codec::tests::*, types::Text};
#[test]
fn decodes() -> Result<(), CodecError> {
let mut bytes = Vec::new();
encode_test_data(&mut bytes);
let mut bytes = bytes.as_slice();
let header: DataHeader = bytes.read_data()?;
assert_eq!(1, header.count);
assert_eq!(0, header.format.ordinal);
assert_eq!(12, header.format.blob_size);
assert_eq!(1, header.format.data_fields);
assert_eq!(TestData::default().num_a, bytes.read_data()?);
assert_eq!(TestData::default().num_b, bytes.read_data()?);
let mut text = Text::default();
bytes.read_data_into(&mut text)?;
assert_eq!(TestData::default().text, text);
Ok(())
}
#[test]
fn splits_off_group_sequences() -> Result<(), CodecError> {
let mut expected = vec![];
encode_test_data(&mut expected);
let mut bytes = vec![];
encode_test_data(&mut bytes);
encode_test_data(&mut bytes);
let original_bytes = bytes.as_slice();
let mut bytes = bytes.as_slice();
let data_one_length = bytes.skip_data()?;
let (data_one, original_bytes) = original_bytes.split_at(data_one_length);
assert_eq!(expected, data_one);
let data_two_length = bytes.skip_data()?;
let (data_two, _) = original_bytes.split_at(data_two_length);
assert_eq!(expected, data_two);
Ok(())
}
}