Skip to content

Commit

Permalink
Add IpAddress.to_prefix_len()
Browse files Browse the repository at this point in the history
Closes: smoltcp-rs#255
Approved by: whitequark
  • Loading branch information
astro authored and Homu committed Jul 31, 2018
1 parent 7920f84 commit 1fbcfb0
Showing 1 changed file with 97 additions and 0 deletions.
97 changes: 97 additions & 0 deletions src/wire/ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down Expand Up @@ -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());
}
}

0 comments on commit 1fbcfb0

Please sign in to comment.