zip-core 0.0.4

zip implementation independent structs and helpers
Documentation
use crate::raw::{ExtensibleData, ExtensibleDataFixed};

use super::{
    preview_u16_from_buf, validate_length, validate_length_fixed, DynamicSizeError, FixedSizeError, Parse, ParseExtend,
};

extern crate alloc;
use alloc::vec;

impl Parse for ExtensibleDataFixed {
    type Error = FixedSizeError;

    fn from_buf<T: bytes::Buf>(buf: &mut T) -> Result<Self, Self::Error>
    where
        Self: Sized,
    {
        let remaining = buf.remaining();
        validate_length(remaining, Self::SIZE_IN_BYTES, FixedSizeError::UnsufficientExactBytes)?;
        Ok(Self {
            header_id: buf.get_u16_le(),
            data_size: buf.get_u16_le(),
        })
    }

    fn to_buf<T: bytes::BufMut>(&self, buf: &mut T) -> Result<(), Self::Error> {
        let remaining = buf.remaining_mut();
        validate_length(remaining, Self::SIZE_IN_BYTES, FixedSizeError::UnsufficientExactBytes)?;
        buf.put_u16_le(self.header_id);
        buf.put_u16_le(self.data_size);
        Ok(())
    }
}

impl ParseExtend for ExtensibleData {
    type Error = DynamicSizeError;
    type Fixed = ExtensibleDataFixed;

    fn from_buf_fixed<T: bytes::Buf>(buf: &mut T, fixed: Self::Fixed) -> Result<Self, (Self::Error, Self::Fixed)>
    where
        Self: Sized,
    {
        let total = fixed.data_size as usize;
        let fixed = validate_length_fixed(buf.remaining(), total, fixed, DynamicSizeError::UnsufficientExactBytes)?;

        let mut data = vec![0; fixed.data_size as usize];
        buf.copy_to_slice(&mut data);

        Ok(Self { fixed, data })
    }
}

impl Parse for ExtensibleData {
    type Error = DynamicSizeError;

    fn from_buf<T: bytes::Buf>(buf: &mut T) -> Result<Self, Self::Error>
    where
        Self: Sized,
    {
        let remaining = buf.remaining();
        const SIZE: usize = ExtensibleDataFixed::SIZE_IN_BYTES;
        validate_length(remaining, SIZE, DynamicSizeError::UnsufficientAtLeastBytes)?;
        const PEEK_START: usize = SIZE - 2;
        let chunk = buf.chunk();
        let data_length: u16 = preview_u16_from_buf(chunk, PEEK_START).ok_or(DynamicSizeError::NotContiguous(SIZE))?;
        let total = SIZE + data_length as usize;
        validate_length(remaining, total, DynamicSizeError::UnsufficientExactBytes)?;

        let fixed = ExtensibleDataFixed::from_buf(buf).map_err(FixedSizeError::in_dynamic)?;
        Self::from_buf_fixed(buf, fixed).map_err(|e| e.0)
    }

    fn to_buf<T: bytes::BufMut>(&self, buf: &mut T) -> Result<(), Self::Error> {
        let remaining = buf.remaining_mut();
        let total = ExtensibleDataFixed::SIZE_IN_BYTES + self.data.len();
        validate_length(remaining, total, DynamicSizeError::UnsufficientExactBytes)?;
        self.fixed.to_buf(buf).map_err(FixedSizeError::in_dynamic)?;
        buf.put_slice(&self.data);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::{super::*, *};

    #[test]
    fn cycle_extensible_data() {
        let data = vec![48, 49, 32];
        let ed = ExtensibleData {
            fixed: ExtensibleDataFixed {
                header_id: 0x0001,
                data_size: data.len() as u16,
            },
            data:  data.clone(),
        };
        let mut buf = vec![];
        ed.to_buf(&mut buf).unwrap();
        assert_eq!(buf.len(), ExtensibleDataFixed::SIZE_IN_BYTES + data.len());
        let mut readbuf = buf.as_slice();
        let ed2 = ExtensibleData::from_buf(&mut readbuf).unwrap();
        assert_eq!(ed, ed2);
        assert_eq!(ed2.data, data);
    }

    #[test]
    fn parseextend_extensible_data() {
        let buf: Vec<u8> = vec![48, 49, 32, 50];
        let mut fixed = ExtensibleDataFixed {
            header_id: 0x0001,
            data_size: buf.len() as u16,
        };
        assert!(ExtensibleData::from_buf_fixed(&mut buf.as_slice(), fixed.clone()).is_ok());
        fixed.data_size += 1;
        assert!(ExtensibleData::from_buf_fixed(&mut buf.as_slice(), fixed).is_err());
    }
}