mirx 0.44.0

MIRX binary image format — flat & chunk-based container for ahead-of-time UI assets
Documentation
use super::*;
use alloc::{vec, vec::Vec};

struct Block(Vec<u8>);
impl Block {
    fn length(&mut self, len: usize) {
        if len >= 15 {
            let mut remaining = len - 15;
            while remaining >= 255 {
                self.0.push(255);
                remaining -= 255;
            }
            self.0.push(remaining as u8);
        }
    }
    fn sequence(&mut self, literals: &[u8], match_: Option<(u16, usize)>) {
        let len = match_.map_or(0, |(_, len)| len - 4);
        self.0
            .push((literals.len().min(15) as u8) << 4 | len.min(15) as u8);
        self.length(literals.len());
        self.0.extend_from_slice(literals);
        if let Some((distance, _)) = match_ {
            self.0.extend_from_slice(&distance.to_le_bytes());
            self.length(len);
        }
    }
}

#[test]
fn profile_has_one_empty_parameter_form_and_no_dictionary() {
    let codec = Lz4::new();
    let record = codec.record();
    assert_eq!(record, CodingRecord::new(CodingId::LZ4, 1, &[]));
    assert_eq!(Lz4::from_record(record), Ok(codec));
    assert_eq!(
        Lz4::from_record(CodingRecord::new(CodingId::RAW, 1, &[])),
        Err(Lz4Error::UnexpectedCoding(CodingId::RAW))
    );
    assert_eq!(
        Lz4::from_record(CodingRecord::new(CodingId::LZ4, 2, &[])),
        Err(Lz4Error::UnsupportedRevision(2))
    );
    assert_eq!(
        Lz4::from_record(CodingRecord::new(CodingId::LZ4, 1, &[0])),
        Err(Lz4Error::UnexpectedParameters)
    );
    assert!(matches!(
        codec.plan(&[0, 1, 0], 4),
        Err(Lz4Error::InvalidOffset { .. })
    ));
    assert!(matches!(
        codec.plan(&[0, 0, 0], 4),
        Err(Lz4Error::InvalidOffset { .. })
    ));
}

#[test]
fn literal_lengths_and_overlapping_matches_preserve_exact_bytes() {
    let codec = Lz4::new();
    for len in [0, 1, 14, 15, 16, 269, 270, 271, 65535] {
        let literals: Vec<_> = (0..len).map(|i| i as u8).collect();
        let mut block = Block(vec![]);
        block.sequence(&literals, None);
        let plan = codec.plan(&block.0, len).unwrap();
        assert_eq!(plan.codec(), codec);
        assert_eq!(plan.input(), block.0);
        assert_eq!(plan.decoded_len(), len);
        let mut output = vec![0xad; len + 1];
        assert_eq!(plan.decode_into(&mut output), Ok(len));
        assert_eq!(output[..len], literals);
        assert_eq!(output[len], 0xad);
    }
    for distance in [1u16, 2, 3, 4, 17, 65535] {
        for len in [7, 18, 19, 20, 273, 274, 275, 1024] {
            let literals: Vec<_> = (0..distance).map(|i| i as u8).collect();
            let mut block = Block(vec![]);
            block.sequence(&literals, Some((distance, len)));
            block.sequence(b"tail!", None);
            let mut expected = literals.clone();
            for i in 0..len {
                expected.push(literals[i % usize::from(distance)]);
            }
            expected.extend_from_slice(b"tail!");
            let mut output = vec![0xad; expected.len() + 1];
            codec
                .plan(&block.0, expected.len())
                .unwrap()
                .decode_into(&mut output)
                .unwrap();
            assert_eq!(output[..expected.len()], expected);
            assert_eq!(output[expected.len()], 0xad);
        }
    }
}

#[test]
fn block_end_limits_are_independent_of_output_capacity() {
    let codec = Lz4::new();
    for tail in 0..=6 {
        for matched in 4..=13 {
            let mut block = Block(vec![]);
            block.sequence(b"a", Some((1, matched)));
            block.sequence(&vec![b'z'; tail], None);
            let result = codec.plan(&block.0, 1 + matched + tail);
            assert_eq!(result.is_ok(), tail >= 5 && matched + tail >= 12);
        }
    }
    for low in 1..=15 {
        assert_eq!(codec.plan(&[low], 0), Err(Lz4Error::InvalidBlockEnd));
    }
    assert_eq!(codec.plan(&[], 0), Err(Lz4Error::Truncated { offset: 0 }));
    assert_eq!(codec.plan(&[0], 0).unwrap().decode_into(&mut []), Ok(0));
    let mut block = Block(vec![]);
    block.sequence(b"a", Some((1, 12)));
    assert!(matches!(
        codec.plan(&block.0, 13),
        Err(Lz4Error::Truncated { .. })
    ));
}

#[test]
fn truncation_counts_and_capacity_are_checked_before_output_writes() {
    let codec = Lz4::new();
    let block = [0x13, b'a', 1, 0, 0x50, b't', b'a', b'i', b'l', b'!'];
    for len in 0..block.len() {
        assert!(codec.plan(&block[..len], 13).is_err());
    }
    for len in [0, 1, 12, 14, usize::MAX] {
        assert!(codec.plan(&block, len).is_err());
    }
    for input in [
        &[0xf0, 255][..],
        &[0x1f, b'a', 1, 0, 255][..],
        &[0x10, b'a', 0][..],
    ] {
        assert!(matches!(
            codec.plan(input, 4096),
            Err(Lz4Error::Truncated { .. })
        ));
    }
    let plan = codec.plan(&block, 13).unwrap();
    let mut output = [0xad; 16];
    assert_eq!(
        plan.decode_into(&mut output[..12]),
        Err(Lz4Error::OutputTooSmall {
            needed: 13,
            available: 12
        })
    );
    assert_eq!(output, [0xad; 16]);
    assert_eq!(plan.decode_into(&mut output), Ok(13));
    assert_eq!(&output[..13], b"aaaaaaaatail!");
    assert_eq!(&output[13..], &[0xad; 3]);
}

#[test]
fn encoder_workspace_is_explicit_bounded_and_reset_per_pass() {
    let codec = Lz4::new();
    for entries in [0, 1, 15, 17, 1000, 65537, 131072] {
        assert!(matches!(
            codec.encoder(&mut vec![0; entries]),
            Err(Lz4Error::InvalidWorkspace { .. })
        ));
    }
    for entries in [16, 64, 256, Lz4::TABLE_LEN, 4096, 65536] {
        let mut table = vec![u32::MAX; entries];
        let mut encoder = codec.encoder(&mut table).unwrap();
        assert_eq!(encoder.table_len(), entries);
        let mut encoded = [0xad; 20];
        let expected = [0x13, b'a', 1, 0, 0x50, b'a', b'a', b'a', b'a', b'a'];
        assert_eq!(encoder.encoded_len(&[b'a'; 13]), Ok(expected.len()));
        assert_eq!(
            encoder.encode_into(&[b'a'; 13], &mut encoded[..9]),
            Err(Lz4Error::OutputTooSmall {
                needed: 10,
                available: 9
            })
        );
        assert_eq!(encoded, [0xad; 20]);
        encoder
            .encode_into(b"xyzxyzxyzxyzxyzxyz", &mut encoded)
            .unwrap();
        encoded.fill(0xad);
        assert_eq!(encoder.encode_into(&[b'a'; 13], &mut encoded), Ok(10));
        assert_eq!(&encoded[..10], &expected);
        assert_eq!(&encoded[10..], &[0xad; 10]);
        assert_eq!(encoder.encode_into(&[], &mut encoded), Ok(1));
        assert_eq!(encoded[0], 0);
        assert_eq!(encoder.encode_into(b"abc", &mut encoded), Ok(4));
        assert_eq!(&encoded[..4], &[0x30, b'a', b'b', b'c']);
    }
    assert_eq!(codec.encoded_bound(0), Ok(16));
    assert!(codec.encoded_bound(usize::MAX).is_err());
    if let Ok(len) = usize::try_from(u64::from(u32::MAX) + 1) {
        assert_eq!(
            codec.encoded_bound(len),
            Err(Lz4Error::InputTooLarge { bytes: len })
        );
    }
}

#[test]
fn encoder_extensions_windows_and_bounds_share_the_decoder_contract() {
    let codec = Lz4::new();
    let mut table = [0; Lz4::TABLE_LEN];
    let mut encoder = codec.encoder(&mut table).unwrap();
    for len in [
        0, 1, 12, 13, 14, 15, 16, 269, 270, 271, 65534, 65535, 65536, 131075,
    ] {
        for period in [1, 3, 17, 251] {
            let input: Vec<_> = (0..len).map(|i| (i % period) as u8).collect();
            let size = encoder.encoded_len(&input).unwrap();
            assert!(size <= codec.encoded_bound(len).unwrap());
            let mut encoded = vec![0xad; size + 1];
            assert_eq!(encoder.encode_into(&input, &mut encoded), Ok(size));
            assert_eq!(encoded[size], 0xad);
            let mut output = vec![0; len];
            codec
                .plan(&encoded[..size], len)
                .unwrap()
                .decode_into(&mut output)
                .unwrap();
            assert_eq!(output, input);
        }
    }

    let mut input = vec![42; 65536];
    input[..4].copy_from_slice(&[1, 2, 3, 4]);
    input.extend_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
    let mut encoded = vec![0; encoder.encoded_len(&input).unwrap()];
    encoder.encode_into(&input, &mut encoded).unwrap();
    let mut output = vec![0; input.len()];
    codec
        .plan(&encoded, input.len())
        .unwrap()
        .decode_into(&mut output)
        .unwrap();
    assert_eq!(output, input);
}