wire-codec 1.2.0

Binary frame codec and protocol codec toolkit. Length-prefixed, varint-prefixed, delimiter-based, checksummed, and custom framing strategies. Built-in varint, zigzag, bitfield, packed struct, CRC, and COBS encoding. Allocation-free core, no_std, runtime-agnostic, with optional tokio-util and futures codec adapters.
Documentation
//! Arbitrary-input harness, run under `cargo test`.
//!
//! Drives the same invariant checks as the libFuzzer targets in `fuzz/`
//! (see `tests/support/fuzz_harness.rs`) with proptest-generated bytes, plus
//! a fixed corpus of inputs that previously exposed bugs or sit on edge
//! cases. This keeps fuzz coverage in every CI job, including Windows and
//! 32-bit targets where `cargo fuzz` is not available.

use proptest::prelude::*;

#[path = "support/fuzz_harness.rs"]
mod harness;

/// Hand-picked inputs: hostile length prefixes (the 32-bit overflow),
/// overlong varints, self-overlapping delimiters, and COBS edge blocks.
const CORPUS: &[&[u8]] = &[
    &[],
    &[0x00],
    &[0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00],
    &[0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00],
    &[0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
    &[0x80, 0x00],
    &[0x80, 0x80, 0x80, 0x80, 0x80, 0x01],
    &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01],
    &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02],
    &[0x01, b'a', b'a', 0x00, b'a', b'a', b'a', b'a'],
    &[0x02, b'a', b'b', b'a', b'x', b'a', b'b', b'a', b'b', b'a'],
    &[0x05, b'\r', b'\n', 0x00, b'x', b'\r', b'\r', b'\n'],
    &[0xFF, 0x01, 0x02, 0x03],
    &[0x01, 0x01, 0x01],
];

#[test]
fn corpus() {
    for input in CORPUS {
        harness::varint(input);
        harness::length_prefixed(input);
        harness::delimited(input);
        harness::varint_prefixed(input);
        harness::checksummed(input);
        harness::bitfield(input);
        harness::cobs(input);
        harness::packed(input);
    }
}

fn bytes() -> impl Strategy<Value = Vec<u8>> {
    // Bias towards bytes that matter to the decoders (zero, continuation
    // bits, all-ones, common delimiters) so short runs hit interesting paths.
    let interesting = prop_oneof![
        3 => any::<u8>(),
        1 => Just(0x00u8),
        1 => Just(0x80u8),
        1 => Just(0xFFu8),
        1 => Just(b'\n'),
        1 => Just(b'a'),
    ];
    proptest::collection::vec(interesting, 0..96)
}

proptest! {
    #![proptest_config(ProptestConfig::with_cases(512))]

    #[test]
    fn varint(data in bytes()) {
        harness::varint(&data);
    }

    #[test]
    fn length_prefixed(data in bytes()) {
        harness::length_prefixed(&data);
    }

    #[test]
    fn delimited(data in bytes()) {
        harness::delimited(&data);
    }

    #[test]
    fn varint_prefixed(data in bytes()) {
        harness::varint_prefixed(&data);
    }

    #[test]
    fn checksummed(data in bytes()) {
        harness::checksummed(&data);
    }

    #[test]
    fn bitfield(data in bytes()) {
        harness::bitfield(&data);
    }

    #[test]
    fn cobs(data in bytes()) {
        harness::cobs(&data);
    }

    #[test]
    fn packed(data in bytes()) {
        harness::packed(&data);
    }
}