craft-codec 0.2.1

Cryptographic Random-Access Framing Toolkit
Documentation
//! Independent range model, persistence validation and integer boundaries.
use craft_codec::{
    Compression, Config, Encryption, Error, FORMAT_VERSION, FrameSizes, Framing, Lengths,
    METADATA_SCHEMA_VERSION, Metadata, MetadataParts,
};

fn config(framing: Framing, compression: Compression, encryption: Encryption) -> Config {
    Config::new(framing, compression, encryption).unwrap()
}

#[test]
fn index_widths_and_length_minus_one_boundaries() {
    for (max, width) in [
        (65_535, 2),
        (65_536, 2),
        (65_537, 4),
        (1 << 32, 4),
        ((1 << 32) + 1, 8),
        (u64::MAX, 8),
    ] {
        let mut lengths = Lengths::new(max).unwrap();
        assert_eq!(lengths.width(), width);
        lengths.push(max).unwrap();
        assert_eq!(lengths.get(0), Some(max));
        assert_eq!(lengths.get(1), None);
        assert!(lengths.push(0).is_err());
        assert_eq!(lengths.len(), 1);
    }
    let mut lengths = Lengths::new(65_536).unwrap();
    lengths.push(65_536).unwrap();
    assert_eq!(lengths, Lengths::U16(vec![u16::MAX]));
    assert_eq!(lengths.push(65_537), Err(Error::Overflow));
    assert_eq!(Lengths::U64(vec![u64::MAX]).get(0), None);
}

#[test]
fn every_logical_range_matches_an_independent_boundary_model() {
    for framing in [Framing::Fixed(7), Framing::Variable(7)] {
        for compression in [Compression::None, Compression::Lz4] {
            for encryption in [Encryption::None, Encryption::Aes256Gcm { key: [0; 32] }] {
                let raw = match framing {
                    Framing::Fixed(_) => vec![7, 7, 7, 3],
                    _ => vec![3, 7, 1, 4],
                };
                let payload: Vec<u64> = raw
                    .iter()
                    .map(|&n| {
                        if compression == Compression::None {
                            n
                        } else {
                            (n / 2).max(1)
                        }
                    })
                    .collect();
                let mut metadata = Metadata::new(config(framing, compression, encryption.clone()));
                for (&raw, &payload) in raw.iter().zip(&payload) {
                    metadata
                        .push(FrameSizes::new(raw, payload).unwrap())
                        .unwrap();
                }
                let mut logical = vec![0];
                let mut physical = vec![0];
                for (&raw, &payload) in raw.iter().zip(&payload) {
                    logical.push(logical.last().unwrap() + raw);
                    physical.push(physical.last().unwrap() + payload + encryption.tag_len() as u64);
                }
                assert_eq!(metadata.logical_len(), *logical.last().unwrap());
                assert_eq!(metadata.stored_len(), *physical.last().unwrap());
                for start in 0..=metadata.logical_len() {
                    for end in start..=metadata.logical_len() {
                        let (query, mut frames) = metadata.range(start, Some(end)).unwrap();
                        let touched: Vec<usize> = (0..raw.len())
                            .filter(|&i| start < end && logical[i] < end && logical[i + 1] > start)
                            .collect();
                        assert_eq!(frames.remaining(), touched.len() as u64);
                        assert_eq!(frames.size_hint(), (touched.len(), Some(touched.len())));
                        if touched.is_empty() {
                            assert_eq!(query, 0..0);
                        } else {
                            assert_eq!(
                                query,
                                physical[touched[0]]..physical[touched[touched.len() - 1] + 1]
                            );
                        }
                        let mut selected = 0;
                        for i in touched {
                            let frame = frames.next().unwrap();
                            assert_eq!(frame.spec.index(), i as u64);
                            assert_eq!(frame.spec.raw_len(), raw[i] as usize);
                            assert_eq!(
                                frame.spec.stored_len(),
                                (physical[i + 1] - physical[i]) as usize
                            );
                            assert_eq!(
                                frame.selected,
                                (start.max(logical[i]) - logical[i]) as usize
                                    ..(end.min(logical[i + 1]) - logical[i]) as usize
                            );
                            selected += frame.selected.len();
                        }
                        assert_eq!(selected as u64, end - start);
                        assert!(frames.next().is_none());
                        assert!(frames.next().is_none());
                    }
                    assert_eq!(
                        metadata.range(start, None).unwrap().0,
                        metadata
                            .range(start, Some(metadata.logical_len()))
                            .unwrap()
                            .0
                    );
                }
                let restored = Metadata::from_parts(metadata.clone().into_parts()).unwrap();
                assert_eq!(restored, metadata);
            }
        }
    }
}

#[test]
fn documented_64k_example_includes_tag_and_preserves_slice() {
    let mut metadata = Metadata::new(config(
        Framing::Fixed(65_536),
        Compression::None,
        Encryption::Aes256Gcm { key: [0; 32] },
    ));
    metadata
        .push(FrameSizes::new(65_536, 65_536).unwrap())
        .unwrap();
    let (query, mut frames) = metadata.range(50, Some(50_213)).unwrap();
    assert_eq!(query, 0..65_552);
    assert_eq!(frames.next().unwrap().selected, 50..50_213);
    assert!(frames.next().is_none());
}

#[test]
fn empty_invalid_and_short_final_frames() {
    let mut metadata = Metadata::new(config(
        Framing::Fixed(8),
        Compression::None,
        Encryption::None,
    ));
    assert!(metadata.range(0, None).unwrap().1.next().is_none());
    assert_eq!(metadata.last_frame_len(), None);
    assert!(metadata.range(1, None).is_err());
    metadata.push(FrameSizes::new(3, 3).unwrap()).unwrap();
    let before = metadata.clone();
    assert_eq!(
        metadata.push(FrameSizes::new(8, 8).unwrap()),
        Err(Error::FrameAfterFinal)
    );
    assert_eq!(metadata, before);
    assert!(metadata.range(2, Some(1)).is_err());
    assert!(metadata.range(0, Some(4)).is_err());
    assert_eq!(metadata.range(3, None).unwrap().0, 0..0);
    assert_eq!(metadata.last_frame_len(), Some(3));
    assert_eq!(metadata.range(1, None).unwrap().0, 0..3);
}

#[test]
fn malformed_persistence_is_rejected() {
    let cfg = config(Framing::Variable(100), Compression::Lz4, Encryption::None);
    let mut metadata = Metadata::new(cfg);
    metadata.push(FrameSizes::new(50, 25).unwrap()).unwrap();
    let base = metadata.into_parts();
    for variant in 0..9 {
        let mut parts = base.clone();
        match variant {
            0 => parts.version = FORMAT_VERSION + 1,
            1 => parts.frame_count = 2,
            2 => parts.last_frame_len = Some(50),
            3 => parts.raw_lengths = None,
            4 => parts.payload_lengths = None,
            5 => parts.raw_lengths = Some(Lengths::U32(vec![49])),
            6 => parts.raw_lengths = Some(Lengths::U16(vec![100])),
            7 => parts.payload_lengths = Some(Lengths::U16(vec![50])),
            8 => parts.raw_lengths = Some(Lengths::U64(vec![u64::MAX])),
            _ => unreachable!(),
        }
        assert!(Metadata::from_parts(parts).is_err(), "variant {variant}");
    }
}

#[test]
fn fixed_metadata_checks_overflow_without_allocating_frames() {
    let cfg = config(Framing::Fixed(8), Compression::None, Encryption::None);
    let mut parts = MetadataParts {
        schema_version: METADATA_SCHEMA_VERSION,
        version: FORMAT_VERSION,
        config: cfg,
        frame_count: u64::MAX,
        last_frame_len: Some(8),
        raw_lengths: None,
        payload_lengths: None,
    };
    assert_eq!(Metadata::from_parts(parts.clone()), Err(Error::Overflow));
    parts.frame_count = 1;
    parts.last_frame_len = Some(9);
    assert_eq!(
        Metadata::from_parts(parts.clone()),
        Err(Error::InvalidMetadata)
    );
    parts.last_frame_len = Some(8);
    parts.raw_lengths = Some(Lengths::U16(vec![7]));
    assert!(Metadata::from_parts(parts).is_err());
}

#[test]
fn large_fixed_ranges_need_no_frame_vector() {
    let cfg = config(Framing::Fixed(1), Compression::None, Encryption::None);
    let metadata = Metadata::from_parts(MetadataParts {
        schema_version: METADATA_SCHEMA_VERSION,
        version: FORMAT_VERSION,
        config: cfg,
        frame_count: u64::MAX,
        last_frame_len: Some(1),
        raw_lengths: None,
        payload_lengths: None,
    })
    .unwrap();
    let (query, mut frames) = metadata.range(u64::MAX - 2, None).unwrap();
    assert_eq!(query, u64::MAX - 2..u64::MAX);
    assert_eq!(frames.next().unwrap().spec.index(), u64::MAX - 2);
    assert_eq!(frames.next().unwrap().spec.index(), u64::MAX - 1);
    assert!(frames.next().is_none());
}