desert_core 0.1.5

Binary serialization library for Rust (core crate)
Documentation
use std::io::Read;

use flate2::read::DeflateDecoder;

use crate::error::Result;
use crate::Error;

pub trait BinaryInput {
    fn read_u8(&mut self) -> Result<u8>;
    fn read_bytes(&mut self, count: usize) -> Result<&[u8]>;
    fn skip(&mut self, count: usize) -> Result<()>;

    fn read_i8(&mut self) -> Result<i8> {
        Ok(self.read_u8()? as i8)
    }

    fn read_u16(&mut self) -> Result<u16> {
        let bytes = self.read_bytes(2)?;
        Ok(u16::from_be_bytes(bytes.try_into()?))
    }

    fn read_i16(&mut self) -> Result<i16> {
        let bytes = self.read_bytes(2)?;
        Ok(i16::from_be_bytes(bytes.try_into()?))
    }

    fn read_u32(&mut self) -> Result<u32> {
        let bytes = self.read_bytes(4)?;
        Ok(u32::from_be_bytes(bytes.try_into()?))
    }

    fn read_i32(&mut self) -> Result<i32> {
        let bytes = self.read_bytes(4)?;
        Ok(i32::from_be_bytes(bytes.try_into()?))
    }

    fn read_u64(&mut self) -> Result<u64> {
        let bytes = self.read_bytes(8)?;
        Ok(u64::from_be_bytes(bytes.try_into()?))
    }

    fn read_i64(&mut self) -> Result<i64> {
        let bytes = self.read_bytes(8)?;
        Ok(i64::from_be_bytes(bytes.try_into()?))
    }

    fn read_u128(&mut self) -> Result<u128> {
        let bytes = self.read_bytes(16)?;
        Ok(u128::from_be_bytes(bytes.try_into()?))
    }

    fn read_i128(&mut self) -> Result<i128> {
        let bytes = self.read_bytes(16)?;
        Ok(i128::from_be_bytes(bytes.try_into()?))
    }

    fn read_f32(&mut self) -> Result<f32> {
        let bytes = self.read_bytes(4)?;
        Ok(f32::from_be_bytes(bytes.try_into()?))
    }

    fn read_f64(&mut self) -> Result<f64> {
        let bytes = self.read_bytes(8)?;
        Ok(f64::from_be_bytes(bytes.try_into()?))
    }

    fn read_var_u32(&mut self) -> Result<u32> {
        let mut result: u32 = 0;
        let mut shift = 0;

        loop {
            let b = self.read_u8()?;
            result |= ((b & 0x7F) as u32) << shift;
            if b & 0x80 == 0 {
                break;
            }
            shift += 7;
            if shift >= 32 {
                return Err(Error::DeserializationFailure(
                    "var_u32 too long".to_string(),
                ));
            }
        }

        Ok(result)
    }

    fn read_var_i32(&mut self) -> Result<i32> {
        let r = self.read_var_u32()?;
        Ok(((r >> 1) ^ (-((r & 1) as i32) as u32)) as i32)
    }

    fn read_compressed(&mut self) -> Result<Vec<u8>> {
        let uncompressed_len = self.read_var_u32()? as usize;
        let compressed_len = self.read_var_u32()? as usize;
        let compressed = self.read_bytes(compressed_len)?;
        let mut deflater = DeflateDecoder::new(compressed);
        let mut result = Vec::with_capacity(uncompressed_len);
        deflater
            .read_to_end(&mut result)
            .map_err(|err| Error::DecompressionFailure(format!("{err}")))?;
        Ok(result)
    }
}

pub struct SliceInput<'a> {
    pub data: &'a [u8],
    pub pos: usize,
}

impl<'a> SliceInput<'a> {
    pub fn new(data: &'a [u8]) -> Self {
        Self { data, pos: 0 }
    }

    pub const EMPTY: Self = Self { data: &[], pos: 0 };
}

impl BinaryInput for SliceInput<'_> {
    fn read_u8(&mut self) -> Result<u8> {
        if self.pos == self.data.len() {
            Err(Error::InputEndedUnexpectedly)
        } else {
            let result = self.data[self.pos];
            self.pos += 1;
            Ok(result)
        }
    }

    fn read_bytes(&mut self, count: usize) -> Result<&[u8]> {
        if self.pos + count > self.data.len() {
            Err(Error::InputEndedUnexpectedly)
        } else {
            let result = &self.data[self.pos..self.pos + count];
            self.pos += count;
            Ok(result)
        }
    }

    fn skip(&mut self, count: usize) -> Result<()> {
        if self.pos + count > self.data.len() {
            Err(Error::InputEndedUnexpectedly)
        } else {
            self.pos += count;
            Ok(())
        }
    }
}

pub struct OwnedInput {
    data: Vec<u8>,
    pos: usize,
}

impl OwnedInput {
    pub fn new(data: Vec<u8>) -> Self {
        Self { data, pos: 0 }
    }
}

impl BinaryInput for OwnedInput {
    fn read_u8(&mut self) -> Result<u8> {
        if self.pos == self.data.len() {
            Err(Error::InputEndedUnexpectedly)
        } else {
            let result = self.data[self.pos];
            self.pos += 1;
            Ok(result)
        }
    }

    fn read_bytes(&mut self, count: usize) -> Result<&[u8]> {
        if self.pos + count > self.data.len() {
            Err(Error::InputEndedUnexpectedly)
        } else {
            let result = &self.data[self.pos..self.pos + count];
            self.pos += count;
            Ok(result)
        }
    }

    fn skip(&mut self, count: usize) -> Result<()> {
        if self.pos + count > self.data.len() {
            Err(Error::InputEndedUnexpectedly)
        } else {
            self.pos += count;
            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::binary_input::OwnedInput;
    use crate::{BinaryInput, BinaryOutput};
    use bytes::BytesMut;
    use proptest::prelude::*;
    use test_r::test;

    proptest! {
        #[test]
        fn roundtrip_var_i32(value: i32) {
            let mut bytes = BytesMut::new();
            bytes.write_var_i32(value);

            let mut bytes = OwnedInput::new(bytes.freeze().to_vec());
            let result = bytes.read_var_i32().unwrap();
            assert_eq!(value, result);
        }

        #[test]
        fn roundtrip_var_u32(value: u32) {
            let mut bytes = BytesMut::new();
            bytes.write_var_u32(value);

            let mut bytes = OwnedInput::new(bytes.freeze().to_vec());
            let result = bytes.read_var_u32().unwrap();
            assert_eq!(value, result);
        }

        #[test]
        fn roundtrip_compressed(bytes: Vec<u8>) {
            let mut compressed = BytesMut::new();
            compressed.write_compressed(&bytes, Default::default()).unwrap();

            let mut compressed = OwnedInput::new(compressed.freeze().to_vec());
            let result = compressed.read_compressed().unwrap();
            assert_eq!(bytes, result);
        }
    }

    #[test]
    fn roundtrip_slice() -> Result<(), crate::Error> {
        let data: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

        let mut bytes = BytesMut::new();
        bytes.write_bytes(&data[2..6]);

        let mut bytes = OwnedInput::new(bytes.freeze().to_vec());
        let result = bytes.read_bytes(4)?;

        assert_eq!(result, &[2, 3, 4, 5]);
        Ok(())
    }
}