@@ -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