rustbinary 0.1.4

A bounded Serde binary codec with adaptive frames, zero-allocation paths, schema evolution, and authenticated pipelines
Documentation
use rustbinary::{
    core::{Error, ErrorCategory},
    protocol::{Fingerprint as _, Reflect as _, StaticSize as _, TypeShape},
};
use serde::{Deserialize, Serialize};

#[derive(
    Debug,
    PartialEq,
    Serialize,
    Deserialize,
    rustbinary::protocol::Fingerprint,
    rustbinary::protocol::Reflect,
    rustbinary::protocol::StaticSize,
)]
struct Header {
    online: bool,
    partition: u16,
    coordinates: [i32; 2],
}

#[derive(Serialize, Deserialize, rustbinary::protocol::Fingerprint)]
struct ReorderedHeader {
    partition: u16,
    online: bool,
    coordinates: [i32; 2],
}

#[derive(Debug, PartialEq, rustbinary::protocol::BitPacked)]
struct PackedFlags {
    online: bool,
    #[bits = 3]
    priority: u8,
    #[bits = 12]
    sequence: u16,
}

fn main() -> rustbinary::Result<()> {
    let value = Header {
        online: true,
        partition: 17,
        coordinates: [-4, 9],
    };
    let base = rustbinary::options().with_limit(4096);

    assert!(base.serialize(&value)?.len() <= Header::MAX_SIZE);
    assert_ne!(
        Header::fingerprint(base),
        ReorderedHeader::fingerprint(base)
    );
    if let TypeShape::Struct(fields) = Header::SHAPE {
        assert_eq!(fields.len(), 3);
        assert_eq!(fields[1].name, "partition");
        assert_eq!(fields[1].type_name, "u16");
    }

    let framed = base.with_fingerprint().serialize(&value)?;
    assert_eq!(
        base.with_fingerprint().deserialize::<Header>(&framed)?,
        value
    );
    assert!(matches!(
        base.with_fingerprint()
            .deserialize::<ReorderedHeader>(&framed),
        Err(Error::SchemaMismatch { .. })
    ));

    let flags = PackedFlags {
        online: true,
        priority: 5,
        sequence: 2047,
    };
    let packed = base.with_bit_packing().serialize(&flags)?;
    assert_eq!(packed.len(), 2);
    assert_eq!(
        base.with_bit_packing()
            .deserialize::<PackedFlags>(&packed)?,
        flags
    );

    let invalid = PackedFlags {
        online: true,
        priority: 8,
        sequence: 1,
    };
    let width_error = base.with_bit_packing().serialize(&invalid).unwrap_err();
    assert!(matches!(
        &width_error,
        Error::BitPacking("unsigned field value is out of range")
    ));
    assert_eq!(width_error.category(), ErrorCategory::Protocol);

    println!(
        "metadata: {} fields, max {} bytes, packed {} bytes, fingerprint {:#018x}",
        match Header::SHAPE {
            TypeShape::Struct(fields) => fields.len(),
            TypeShape::Enum(_) => 0,
        },
        Header::MAX_SIZE,
        packed.len(),
        Header::fingerprint(base)
    );

    Ok(())
}