net-wire 0.1.0

Allocation-free no_std wire views and codecs for network protocols.
Documentation
use net_wire::http2::hpack::{
    HpackIntegerParseError, HpackStringLiteral, HpackStringLiteralBuildError,
    HpackStringLiteralBuilder, HpackStringLiteralParseError,
};

#[test]
fn hpack_string_literal_parses_plain_and_huffman_opaque_payloads() {
    let plain_wire = b"\x0fwww.example.comsuffix";
    let plain = HpackStringLiteral::parse(plain_wire).unwrap();
    assert_eq!(plain.as_bytes(), b"\x0fwww.example.com");
    assert!(!plain.is_huffman());
    assert_eq!(plain.encoded_bytes(), b"www.example.com");
    assert_eq!(plain.length().as_bytes(), [0x0f]);
    assert_eq!(plain.length().value(), 15);

    let huffman_wire = [0x83, 0xff, 0x00, 0xa5, 0xde];
    let huffman = HpackStringLiteral::parse(&huffman_wire).unwrap();
    assert_eq!(huffman.as_bytes(), &huffman_wire[..4]);
    assert!(huffman.is_huffman());
    assert_eq!(huffman.encoded_bytes(), [0xff, 0x00, 0xa5]);
    assert_eq!(huffman.length().as_bytes(), [0x83]);
}

#[test]
fn hpack_string_literal_preserves_long_and_overlong_length_representations() {
    let long_payload = [0x5a; 127];
    let mut long_wire = vec![0x7f, 0x00];
    long_wire.extend_from_slice(&long_payload);
    long_wire.push(0xaa);
    let long = HpackStringLiteral::parse(&long_wire).unwrap();
    assert_eq!(long.as_bytes(), &long_wire[..129]);
    assert_eq!(long.length().as_bytes(), [0x7f, 0x00]);
    assert_eq!(long.encoded_bytes(), long_payload);

    let mut overlong_wire = vec![0x7f, 0x80, 0x00];
    overlong_wire.extend_from_slice(&long_payload);
    overlong_wire.push(0xaa);
    let overlong = HpackStringLiteral::parse(&overlong_wire).unwrap();
    assert_eq!(overlong.as_bytes(), &overlong_wire[..130]);
    assert_eq!(overlong.length().as_bytes(), [0x7f, 0x80, 0x00]);
    assert_eq!(overlong.length().value(), 127);
    assert_eq!(overlong.encoded_bytes(), long_payload);
}

#[test]
fn hpack_string_literal_propagates_length_errors_and_payload_truncation() {
    assert_eq!(
        HpackStringLiteral::parse(&[]),
        Err(HpackStringLiteralParseError::InvalidLength(
            HpackIntegerParseError::Incomplete {
                required: 1,
                available: 0,
            }
        ))
    );
    assert_eq!(
        HpackStringLiteral::parse(&[0x7f]),
        Err(HpackStringLiteralParseError::InvalidLength(
            HpackIntegerParseError::Incomplete {
                required: 2,
                available: 1,
            }
        ))
    );
    assert_eq!(
        HpackStringLiteral::parse(&[
            0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02,
        ]),
        Err(HpackStringLiteralParseError::InvalidLength(
            HpackIntegerParseError::Overflow
        ))
    );
    assert_eq!(
        HpackStringLiteral::parse(&[0x03, 0xaa, 0xbb]),
        Err(HpackStringLiteralParseError::IncompleteEncodedPayload {
            required: 3,
            available: 2,
        })
    );
}

#[test]
fn hpack_string_literal_builder_writes_exact_bytes_and_preserves_suffix() {
    let mut plain_destination = [0xaa; 24];
    let plain =
        HpackStringLiteralBuilder::new_encoded(&mut plain_destination, false, b"www.example.com")
            .build()
            .unwrap();
    assert_eq!(plain.as_bytes(), b"\x0fwww.example.com");
    assert!(!plain.is_huffman());
    assert_eq!(plain_destination[16..], [0xaa; 8]);

    let mut huffman_destination = [0xaa; 8];
    let huffman =
        HpackStringLiteralBuilder::new_encoded(&mut huffman_destination, true, &[0xff, 0x00, 0xa5])
            .build()
            .unwrap();
    assert_eq!(huffman.as_bytes(), [0x83, 0xff, 0x00, 0xa5]);
    assert!(huffman.is_huffman());
    assert_eq!(huffman_destination[4..], [0xaa; 4]);

    let long_payload = [0x5a; 127];
    let mut long_destination = [0xaa; 132];
    let long = HpackStringLiteralBuilder::new_encoded(&mut long_destination, false, &long_payload)
        .build()
        .unwrap();
    assert_eq!(
        long.as_bytes(),
        [&[0x7f, 0x00][..], &long_payload[..]].concat()
    );
    assert_eq!(long_destination[129..], [0xaa; 3]);
}

#[test]
fn hpack_string_literal_builder_failures_are_atomic() {
    let mut destination = [0xaa; 3];
    let before = destination;
    assert_eq!(
        HpackStringLiteralBuilder::new_encoded(&mut destination, true, &[0xff, 0x00, 0xa5]).build(),
        Err(HpackStringLiteralBuildError::BufferTooShort {
            required: 4,
            available: 3,
        })
    );
    assert_eq!(destination, before);
}