Skip to content

Commit 565cdad

Browse files
astrowhitequark
authored andcommitted
Add IpAddress.to_prefix_len()
1 parent 3f68033 commit 565cdad

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

src/wire/ip.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,34 @@ impl Address {
184184
&Address::__Nonexhaustive => unreachable!()
185185
}
186186
}
187+
188+
/// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
189+
/// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
190+
pub fn to_prefix_len(&self) -> Option<u8> {
191+
let mut ones = true;
192+
let mut prefix_len = 0;
193+
for byte in self.as_bytes() {
194+
let mut mask = 0x80;
195+
for _ in 0..8 {
196+
let one = *byte & mask != 0;
197+
if ones {
198+
// Expect 1s until first 0
199+
if one {
200+
prefix_len += 1;
201+
} else {
202+
ones = false;
203+
}
204+
} else {
205+
if one {
206+
// 1 where 0 was expected
207+
return None
208+
}
209+
}
210+
mask >>= 1;
211+
}
212+
}
213+
Some(prefix_len)
214+
}
187215
}
188216

189217
#[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
@@ -1074,4 +1102,73 @@ pub(crate) mod test {
10741102
fn endpoint_unspecified() {
10751103
assert!(!Endpoint::UNSPECIFIED.is_specified());
10761104
}
1105+
1106+
#[test]
1107+
#[cfg(feature = "proto-ipv4")]
1108+
fn to_prefix_len_ipv4() {
1109+
fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
1110+
assert_eq!(
1111+
Some(prefix_len),
1112+
mask.into().to_prefix_len()
1113+
);
1114+
}
1115+
1116+
test_eq(0, Ipv4Address::new(0, 0, 0, 0));
1117+
test_eq(1, Ipv4Address::new(128, 0, 0, 0));
1118+
test_eq(2, Ipv4Address::new(192, 0, 0, 0));
1119+
test_eq(3, Ipv4Address::new(224, 0, 0, 0));
1120+
test_eq(4, Ipv4Address::new(240, 0, 0, 0));
1121+
test_eq(5, Ipv4Address::new(248, 0, 0, 0));
1122+
test_eq(6, Ipv4Address::new(252, 0, 0, 0));
1123+
test_eq(7, Ipv4Address::new(254, 0, 0, 0));
1124+
test_eq(8, Ipv4Address::new(255, 0, 0, 0));
1125+
test_eq(9, Ipv4Address::new(255, 128, 0, 0));
1126+
test_eq(10, Ipv4Address::new(255, 192, 0, 0));
1127+
test_eq(11, Ipv4Address::new(255, 224, 0, 0));
1128+
test_eq(12, Ipv4Address::new(255, 240, 0, 0));
1129+
test_eq(13, Ipv4Address::new(255, 248, 0, 0));
1130+
test_eq(14, Ipv4Address::new(255, 252, 0, 0));
1131+
test_eq(15, Ipv4Address::new(255, 254, 0, 0));
1132+
test_eq(16, Ipv4Address::new(255, 255, 0, 0));
1133+
test_eq(17, Ipv4Address::new(255, 255, 128, 0));
1134+
test_eq(18, Ipv4Address::new(255, 255, 192, 0));
1135+
test_eq(19, Ipv4Address::new(255, 255, 224, 0));
1136+
test_eq(20, Ipv4Address::new(255, 255, 240, 0));
1137+
test_eq(21, Ipv4Address::new(255, 255, 248, 0));
1138+
test_eq(22, Ipv4Address::new(255, 255, 252, 0));
1139+
test_eq(23, Ipv4Address::new(255, 255, 254, 0));
1140+
test_eq(24, Ipv4Address::new(255, 255, 255, 0));
1141+
test_eq(25, Ipv4Address::new(255, 255, 255, 128));
1142+
test_eq(26, Ipv4Address::new(255, 255, 255, 192));
1143+
test_eq(27, Ipv4Address::new(255, 255, 255, 224));
1144+
test_eq(28, Ipv4Address::new(255, 255, 255, 240));
1145+
test_eq(29, Ipv4Address::new(255, 255, 255, 248));
1146+
test_eq(30, Ipv4Address::new(255, 255, 255, 252));
1147+
test_eq(31, Ipv4Address::new(255, 255, 255, 254));
1148+
test_eq(32, Ipv4Address::new(255, 255, 255, 255));
1149+
}
1150+
1151+
#[cfg(feature = "proto-ipv4")]
1152+
fn to_prefix_len_ipv4_error() {
1153+
assert_eq!(None, IpAddress::from(Ipv4Address::new(255,255,255,1)).to_prefix_len());
1154+
}
1155+
1156+
#[test]
1157+
#[cfg(feature = "proto-ipv6")]
1158+
fn to_prefix_len_ipv6() {
1159+
fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
1160+
assert_eq!(
1161+
Some(prefix_len),
1162+
mask.into().to_prefix_len()
1163+
);
1164+
}
1165+
1166+
test_eq(0, Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 0));
1167+
test_eq(128, Ipv6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff));
1168+
}
1169+
1170+
#[cfg(feature = "proto-ipv6")]
1171+
fn to_prefix_len_ipv6_error() {
1172+
assert_eq!(None, IpAddress::from(Ipv6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0, 1)).to_prefix_len());
1173+
}
10771174
}

0 commit comments

Comments
 (0)