use crate::{
error::{InstanceError, TypeError},
lib::*,
ser::BYTES_PER_LENGTH_OFFSET,
SimpleSerialize,
};
#[derive(Debug)]
pub enum DeserializeError {
ExpectedFurtherInput { provided: usize, expected: usize },
AdditionalInput { provided: usize, expected: usize },
InvalidByte(u8),
InvalidInstance(InstanceError),
InvalidType(TypeError),
InvalidOffsetsLength(usize),
OffsetNotIncreasing { start: usize, end: usize },
}
impl From<InstanceError> for DeserializeError {
fn from(err: InstanceError) -> Self {
Self::InvalidInstance(err)
}
}
impl From<TypeError> for DeserializeError {
fn from(err: TypeError) -> Self {
Self::InvalidType(err)
}
}
impl Display for DeserializeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
DeserializeError::ExpectedFurtherInput { provided, expected } => write!(f, "expected at least {expected} byte(s) when decoding but provided only {provided} byte(s)"),
DeserializeError::AdditionalInput { provided, expected } => write!(f, "{provided} byte(s) given but only expected (up to) {expected} byte(s)"),
DeserializeError::InvalidByte(b) => write!(
f,
"invalid byte {b:x} when decoding data of the expected type"
),
DeserializeError::InvalidInstance(err) => write!(f, "invalid instance: {err}"),
DeserializeError::InvalidType(err) => write!(f, "invalid type: {err}"),
DeserializeError::InvalidOffsetsLength(len) => write!(f, "the offsets length provided {len} is not a multiple of the size per length offset {BYTES_PER_LENGTH_OFFSET} bytes"),
DeserializeError::OffsetNotIncreasing { start, end } => write!(f, "invalid offset points to byte {end} before byte {start}"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DeserializeError {}
pub trait Deserialize {
fn deserialize(encoding: &[u8]) -> Result<Self, DeserializeError>
where
Self: Sized;
}
fn deserialize_fixed_homogeneous_composite<T>(encoding: &[u8]) -> Result<Vec<T>, DeserializeError>
where
T: SimpleSerialize,
{
debug_assert_eq!(encoding.len() % T::size_hint(), 0);
let mut elements = vec![];
for chunk in encoding.chunks_exact(T::size_hint()) {
let element = T::deserialize(chunk)?;
elements.push(element);
}
Ok(elements)
}
fn deserialize_variable_homogeneous_composite<T>(
encoding: &[u8],
) -> Result<Vec<T>, DeserializeError>
where
T: SimpleSerialize,
{
if encoding.is_empty() {
return Ok(vec![])
}
let offsets_len = encoding.get(..BYTES_PER_LENGTH_OFFSET).ok_or({
DeserializeError::ExpectedFurtherInput {
provided: encoding.len(),
expected: BYTES_PER_LENGTH_OFFSET,
}
})?;
let offsets_len = u32::deserialize(offsets_len)?;
let offsets_len = offsets_len as usize;
if encoding.len() < offsets_len {
return Err(DeserializeError::ExpectedFurtherInput {
provided: encoding.len(),
expected: offsets_len,
})
}
if offsets_len % BYTES_PER_LENGTH_OFFSET != 0 {
return Err(DeserializeError::InvalidOffsetsLength(offsets_len))
}
let offsets = &mut encoding[..offsets_len]
.chunks_exact(BYTES_PER_LENGTH_OFFSET)
.map(|chunk| u32::deserialize(chunk).map(|offset| offset as usize))
.collect::<Result<Vec<usize>, DeserializeError>>()?;
offsets.push(encoding.len());
let element_count = offsets_len / BYTES_PER_LENGTH_OFFSET;
let mut result = Vec::with_capacity(element_count);
for span in offsets.windows(2) {
let start = span[0];
let end = span[1];
if start > end {
return Err(DeserializeError::OffsetNotIncreasing { start, end })
}
let element = T::deserialize(&encoding[start..end])?;
result.push(element);
}
Ok(result)
}
pub fn deserialize_homogeneous_composite<T>(encoding: &[u8]) -> Result<Vec<T>, DeserializeError>
where
T: SimpleSerialize,
{
if T::is_variable_size() {
deserialize_variable_homogeneous_composite(encoding)
} else {
deserialize_fixed_homogeneous_composite(encoding)
}
}