cbor_enhanced 0.1.1

Cbor de/serialization library making use of lifetimes to support zero copy deserialization. Several iana tags are supported but need to be activated via feature flags.
Documentation
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

use crate::de::{Deserializer, Remaining};
use crate::error::CborError;
use crate::types::IanaTag;
use crate::Deserialize;

impl<'de> Deserializer {
    pub fn take_ip_address(&self, data: &'de [u8]) -> Result<(IpAddr, Remaining<'de>), CborError> {
        let remaining = self.expect_tag(data, IanaTag::NetworkAddress)?;
        let (slice, remaining) = self.take_bytes(remaining, true)?;

        if slice.len() == 4 {
            let octets = [slice[0], slice[1], slice[2], slice[3]];
            let v4_addr = Ipv4Addr::from(octets);
            Ok((IpAddr::V4(v4_addr), remaining))
        } else if slice.len() == 16 {
            let octets = [
                slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
                slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14],
                slice[15],
            ];
            let v6_addr = Ipv6Addr::from(octets);
            Ok((IpAddr::V6(v6_addr), remaining))
        } else {
            Err(CborError::InvalidArrayLength {
                expected: &[4, 16],
                got: slice.len(),
            })
        }
    }
    pub fn take_ip_address_and_mask(
        &self,
        data: &'de [u8],
    ) -> Result<((IpAddr, u8), Remaining<'de>), CborError> {
        let remaining = self.expect_tag(data, IanaTag::NetworkAddressPlusMask)?;
        let (length, remaining) = self.take_map_def(remaining, true)?;

        if length.unwrap_or(0) != 1 {
            return Err(CborError::InvalidArrayLength {
                expected: &[1],
                got: length.unwrap_or(0),
            });
        }

        let (slice, remaining) = self.take_bytes(remaining, true)?;
        let (prefix_length, remaining) = self.take_unsigned(remaining, true)?;

        if slice.len() == 4 {
            let octets = [slice[0], slice[1], slice[2], slice[3]];
            let v4_addr = Ipv4Addr::from(octets);
            Ok(((IpAddr::V4(v4_addr), prefix_length as u8), remaining))
        } else if slice.len() == 16 {
            let octets = [
                slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
                slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14],
                slice[15],
            ];
            let v6_addr = Ipv6Addr::from(octets);
            Ok(((IpAddr::V6(v6_addr), prefix_length as u8), remaining))
        } else {
            Err(CborError::InvalidArrayLength {
                expected: &[4, 16],
                got: slice.len(),
            })
        }
    }
    pub fn take_mac_address(
        &self,
        data: &'de [u8],
    ) -> Result<([u8; 6], Remaining<'de>), CborError> {
        let remaining = self.expect_tag(data, IanaTag::NetworkAddress)?;
        let (slice, remaining) = self.take_bytes(remaining, true)?;

        if slice.len() == 6 {
            let octets = [slice[0], slice[1], slice[2], slice[3], slice[4], slice[5]];
            Ok((octets, remaining))
        } else {
            Err(CborError::InvalidArrayLength {
                expected: &[6],
                got: slice.len(),
            })
        }
    }
}
impl<'de> Deserialize<'de> for IpAddr {
    fn deserialize(
        deserializer: &mut Deserializer,
        data: &'de [u8],
    ) -> Result<(Self, &'de [u8]), CborError> {
        deserializer
            .take_ip_address(data)
            .map(|(v, remaining)| (v, remaining))
    }
}

#[cfg(test)]
mod tests {
    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

    use crate::de::Deserializer;

    #[test]
    fn test_take_ipv4() {
        let slice = b"\xd9\x01\x04\x44\xc0\x0a\x0a\x01";
        let (address, _) = Deserializer::new().take_ip_address(slice).unwrap();
        let expected: Ipv4Addr = "192.10.10.1".parse().unwrap();
        match address {
            IpAddr::V4(v4) => assert_eq!(expected, v4),
            IpAddr::V6(_) => panic!("expected v4"),
        }
    }

    #[test]
    fn test_take_mac() {
        let slice = b"\xd9\x01\x04\x46\x01\x23\x45\x67\x89\xab";
        let (address, _) = Deserializer::new().take_mac_address(slice).unwrap();
        let expected = b"\x01\x23\x45\x67\x89\xab";
        assert_eq!(address, *expected);
    }

    #[test]
    fn test_take_ipv6() {
        let slice =
            b"\xd9\x01\x04\x50\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34";
        let (address, _) = Deserializer::new().take_ip_address(slice).unwrap();
        let expected: Ipv6Addr = "2001:db8:85a3::8a2e:370:7334".parse().unwrap();
        match address {
            IpAddr::V6(v6) => assert_eq!(expected, v6),
            IpAddr::V4(_) => panic!("expected v6"),
        }
    }

    #[test]
    fn test_take_ipv4_and_mask() {
        let slice = b"\xd9\x01\x05\xa1\x44\xc0\xa8\x00\x64\x18\x18";
        let ((address, length), _) = Deserializer::new().take_ip_address_and_mask(slice).unwrap();
        let expected: Ipv4Addr = "192.168.0.100".parse().unwrap();
        match address {
            IpAddr::V4(v4) => assert_eq!(expected, v4),
            IpAddr::V6(_) => panic!("expected v4"),
        }
        assert_eq!(24, length);
    }
}