Add IpAddress.to_prefix_len()

Closes: #255
Approved by: whitequark
v0.7.x
Astro 2018-07-24 22:03:59 +02:00 committed by Homu
parent 633d89b78e
commit c2c08b4c35
1 changed files with 97 additions and 0 deletions

View File

@ -184,6 +184,34 @@ impl Address {
&Address::__Nonexhaustive => unreachable!()
}
}
/// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
/// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
pub fn to_prefix_len(&self) -> Option<u8> {
let mut ones = true;
let mut prefix_len = 0;
for byte in self.as_bytes() {
let mut mask = 0x80;
for _ in 0..8 {
let one = *byte & mask != 0;
if ones {
// Expect 1s until first 0
if one {
prefix_len += 1;
} else {
ones = false;
}
} else {
if one {
// 1 where 0 was expected
return None
}
}
mask >>= 1;
}
}
Some(prefix_len)
}
}
#[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
@ -1074,4 +1102,73 @@ pub(crate) mod test {
fn endpoint_unspecified() {
assert!(!Endpoint::UNSPECIFIED.is_specified());
}
#[test]
#[cfg(feature = "proto-ipv4")]
fn to_prefix_len_ipv4() {
fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
assert_eq!(
Some(prefix_len),
mask.into().to_prefix_len()
);
}
test_eq(0, Ipv4Address::new(0, 0, 0, 0));
test_eq(1, Ipv4Address::new(128, 0, 0, 0));
test_eq(2, Ipv4Address::new(192, 0, 0, 0));
test_eq(3, Ipv4Address::new(224, 0, 0, 0));
test_eq(4, Ipv4Address::new(240, 0, 0, 0));
test_eq(5, Ipv4Address::new(248, 0, 0, 0));
test_eq(6, Ipv4Address::new(252, 0, 0, 0));
test_eq(7, Ipv4Address::new(254, 0, 0, 0));
test_eq(8, Ipv4Address::new(255, 0, 0, 0));
test_eq(9, Ipv4Address::new(255, 128, 0, 0));
test_eq(10, Ipv4Address::new(255, 192, 0, 0));
test_eq(11, Ipv4Address::new(255, 224, 0, 0));
test_eq(12, Ipv4Address::new(255, 240, 0, 0));
test_eq(13, Ipv4Address::new(255, 248, 0, 0));
test_eq(14, Ipv4Address::new(255, 252, 0, 0));
test_eq(15, Ipv4Address::new(255, 254, 0, 0));
test_eq(16, Ipv4Address::new(255, 255, 0, 0));
test_eq(17, Ipv4Address::new(255, 255, 128, 0));
test_eq(18, Ipv4Address::new(255, 255, 192, 0));
test_eq(19, Ipv4Address::new(255, 255, 224, 0));
test_eq(20, Ipv4Address::new(255, 255, 240, 0));
test_eq(21, Ipv4Address::new(255, 255, 248, 0));
test_eq(22, Ipv4Address::new(255, 255, 252, 0));
test_eq(23, Ipv4Address::new(255, 255, 254, 0));
test_eq(24, Ipv4Address::new(255, 255, 255, 0));
test_eq(25, Ipv4Address::new(255, 255, 255, 128));
test_eq(26, Ipv4Address::new(255, 255, 255, 192));
test_eq(27, Ipv4Address::new(255, 255, 255, 224));
test_eq(28, Ipv4Address::new(255, 255, 255, 240));
test_eq(29, Ipv4Address::new(255, 255, 255, 248));
test_eq(30, Ipv4Address::new(255, 255, 255, 252));
test_eq(31, Ipv4Address::new(255, 255, 255, 254));
test_eq(32, Ipv4Address::new(255, 255, 255, 255));
}
#[cfg(feature = "proto-ipv4")]
fn to_prefix_len_ipv4_error() {
assert_eq!(None, IpAddress::from(Ipv4Address::new(255,255,255,1)).to_prefix_len());
}
#[test]
#[cfg(feature = "proto-ipv6")]
fn to_prefix_len_ipv6() {
fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
assert_eq!(
Some(prefix_len),
mask.into().to_prefix_len()
);
}
test_eq(0, Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 0));
test_eq(128, Ipv6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff));
}
#[cfg(feature = "proto-ipv6")]
fn to_prefix_len_ipv6_error() {
assert_eq!(None, IpAddress::from(Ipv6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0, 1)).to_prefix_len());
}
}