bitsandbytes 0.1.0

An owned, bit-aware binary codec: fast bit/byte field types and the unified #[bin] macro.
Documentation
//! `#[reserved]` / `#[reserved_with]`: a reserved field is a normal **stored** field
//! with a known *spec value* (the type's zero, or the `reserved_with` expression). On
//! the default path it reads/writes its actual value — so a peer's reserved bits are
//! observable and overridable (dual-use). The builder defaults it to the spec value
//! (so it isn't required), and the `spec_*` codecs use the spec value instead.

use bnb::{bin, u3, u4};

#[bin]
#[derive(Debug, PartialEq, Eq, Clone)]
struct Frame {
    version: u4,
    #[reserved]
    rsv: u4,
    payload: u8,
}

#[test]
fn builder_defaults_reserved_to_spec_but_allows_override() {
    // Optional in the builder: omitting it defaults to the spec value (0).
    let f = Frame::builder()
        .version(u4::new(5))
        .payload(0xAB)
        .build()
        .unwrap();
    assert_eq!(f.rsv, u4::new(0));
    assert_eq!(f.to_bytes().unwrap(), [0x50, 0xAB]); // version(0101) reserved(0000)

    // ...but you can override it to emit non-spec reserved bits.
    let g = Frame::builder()
        .version(u4::new(5))
        .rsv(u4::new(0xF))
        .payload(0xAB)
        .build()
        .unwrap();
    assert_eq!(g.to_bytes().unwrap(), [0x5F, 0xAB]); // the actual value on the wire
    assert_eq!(g.to_spec_bytes().unwrap(), [0x50, 0xAB]); // the spec value on the wire
}

#[test]
fn decode_captures_actual_bits_spec_decode_reports_spec() {
    // The default decoder captures the actual reserved bits from the wire...
    let actual = Frame::decode_exact(&[0x5F, 0xAB]).unwrap();
    assert_eq!(actual.rsv, u4::new(0xF));
    assert_eq!(actual.payload, 0xAB);

    // ...spec_decode reports the value we *expect* (the spec), discarding the wire bits.
    let spec = Frame::spec_decode_exact(&[0x5F, 0xAB]).unwrap();
    assert_eq!(spec.rsv, u4::new(0));
    assert_eq!(spec.version, u4::new(5)); // non-reserved fields are unchanged
    assert_eq!(spec.payload, 0xAB);
}

#[bin]
#[derive(Debug, PartialEq, Eq, Clone)]
struct Frame2 {
    tag: u4,
    #[reserved_with(u3::new(0b111))]
    must_be_one: u3,
    rest: u4,
}

#[test]
fn reserved_with_spec_value_is_the_pattern() {
    // The builder defaults the reserved field to the must-be-one pattern.
    let f = Frame2::builder()
        .tag(u4::new(0xA))
        .rest(u4::new(0x5))
        .build()
        .unwrap();
    assert_eq!(f.must_be_one, u3::new(0b111));
    assert_eq!(f.to_bytes().unwrap()[0], 0xAE); // tag(1010) reserved(111) rest-high(0)

    // Override to a non-spec value: it goes on the wire; to_spec_bytes forces the
    // pattern back; spec_decode reports the expected pattern regardless of the wire.
    let g = Frame2 {
        tag: u4::new(0xA),
        must_be_one: u3::new(0),
        rest: u4::new(0x5),
    };
    assert_eq!(g.to_bytes().unwrap()[0], 0xA0); // reserved(000)
    assert_eq!(g.to_spec_bytes().unwrap()[0], 0xAE); // reserved forced to 111
    assert_eq!(
        Frame2::spec_decode_exact(&g.to_bytes().unwrap())
            .unwrap()
            .must_be_one,
        u3::new(0b111)
    );
}