zrip-core 0.5.1

Shared types and codecs for zrip (internal crate)
Documentation
#![forbid(unsafe_code)]

use crate::error::DecompressError;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlockType {
    Raw,
    Rle,
    Compressed,
}

#[derive(Debug, Clone, Copy)]
pub struct BlockHeader {
    pub last_block: bool,
    pub block_type: BlockType,
    pub block_size: u32,
}

pub fn parse_block_header(data: &[u8]) -> Result<BlockHeader, DecompressError> {
    if data.len() < 3 {
        return Err(DecompressError::InputExhausted);
    }

    let raw = u32::from_le_bytes([data[0], data[1], data[2], 0]);

    let last_block = (raw & 1) != 0;
    let block_type_bits = (raw >> 1) & 0x03;
    let block_size = raw >> 3;

    let block_type = match block_type_bits {
        0 => BlockType::Raw,
        1 => BlockType::Rle,
        2 => BlockType::Compressed,
        _ => return Err(DecompressError::BadBlockType),
    };

    Ok(BlockHeader {
        last_block,
        block_type,
        block_size,
    })
}

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

    #[test]
    fn parse_raw_block() {
        let data = [0x00, 0x00, 0x01];
        let hdr = parse_block_header(&data).unwrap();
        assert!(!hdr.last_block);
        assert_eq!(hdr.block_type, BlockType::Raw);
        assert_eq!(hdr.block_size, 0x0001_0000 >> 3);
    }

    #[test]
    fn parse_last_compressed() {
        let data = [0x05, 0x00, 0x00];
        let hdr = parse_block_header(&data).unwrap();
        assert!(hdr.last_block);
        assert_eq!(hdr.block_type, BlockType::Compressed);
        assert_eq!(hdr.block_size, 0);
    }
}