net-wire 0.1.0

Allocation-free no_std wire views and codecs for network protocols.
Documentation
use net_wire::ParseError;
use net_wire::icmpv4::{Icmpv4Message, Icmpv4MessageMut, Icmpv4Type};

fn checksum(bytes: &[u8]) -> u16 {
    let mut sum = 0u32;
    for pair in bytes.chunks(2) {
        sum += u32::from(u16::from_be_bytes([pair[0], *pair.get(1).unwrap_or(&0)]));
    }
    while sum >> 16 != 0 {
        sum = (sum & 0xffff) + (sum >> 16);
    }
    !(sum as u16)
}

#[test]
fn parsing_is_checksum_permissive_and_has_a_known_vector() {
    let invalid = [0xfe, 0xa5, 0x43, 0x56, 1, 2, 3];
    let message = Icmpv4Message::parse(&invalid).unwrap();
    assert_eq!(
        (
            message.message_type().raw(),
            message.code(),
            message.checksum(),
            message.body()
        ),
        (0xfe, 0xa5, 0x4356, &[1, 2, 3][..])
    );
    assert_eq!(message.as_bytes(), &invalid);
    assert!(!message.checksum_is_valid());
    assert_eq!(
        Icmpv4Message::parse(&invalid[..3]),
        Err(ParseError::Truncated {
            minimum: 4,
            available: 3
        })
    );

    let known = [8, 0, 0x4d, 0xfc, 0, 1, 0, 2, 0xaa];
    assert_eq!(checksum(&[8, 0, 0, 0, 0, 1, 0, 2, 0xaa]), 0x4dfc);
    assert!(Icmpv4Message::parse(&known).unwrap().checksum_is_valid());
}

#[test]
fn mutable_setters_and_raw_bytes_leave_checksum_stale_until_updated() {
    let mut bytes = [8, 0, 0x4d, 0xfc, 0, 1, 0, 2, 0xaa];
    let mut message = Icmpv4MessageMut::parse(&mut bytes).unwrap();
    message.set_message_type(Icmpv4Type::ECHO_REPLY);
    message.set_code(9);
    message.set_checksum(0xbeef);
    message.body_mut()[0] = 7;
    message.as_bytes_mut()[8] = 3;
    assert_eq!(message.as_bytes(), &[0, 9, 0xbe, 0xef, 7, 1, 0, 2, 3]);
    assert!(!message.checksum_is_valid());
    message.update_checksum();
    assert_eq!(message.checksum(), checksum(&[0, 9, 0, 0, 7, 1, 0, 2, 3]));
    assert!(message.checksum_is_valid());
}