@@ -184,6 +184,33 @@ impl Address {
184184 & Address :: __Nonexhaustive => unreachable ! ( )
185185 }
186186 }
187+
188+ /// Treat as subnet mask, get position of first 0
189+ pub fn to_prefix_len ( & self ) -> Option < u8 > {
190+ let mut ones = true ;
191+ let mut prefix_len = 0 ;
192+ for byte in self . as_bytes ( ) {
193+ let mut mask = 0x80 ;
194+ for _ in 0 ..8 {
195+ let one = * byte & mask != 0 ;
196+ if ones {
197+ // Expect 1s until first 0
198+ if one {
199+ prefix_len += 1 ;
200+ } else {
201+ ones = false ;
202+ }
203+ } else {
204+ if one {
205+ // 1 where 0 was expected
206+ return None ;
207+ }
208+ }
209+ mask >>= 1 ;
210+ }
211+ }
212+ Some ( prefix_len)
213+ }
187214}
188215
189216#[ cfg( all( feature = "std" , feature = "proto-ipv4" , feature = "proto-ipv6" ) ) ]
@@ -1074,4 +1101,73 @@ pub(crate) mod test {
10741101 fn endpoint_unspecified ( ) {
10751102 assert ! ( !Endpoint :: UNSPECIFIED . is_specified( ) ) ;
10761103 }
1104+
1105+ #[ test]
1106+ #[ cfg( feature = "proto-ipv4" ) ]
1107+ fn to_prefix_len_ipv4 ( ) {
1108+ fn test_eq < A : Into < Address > > ( prefix_len : u8 , mask : A ) {
1109+ assert_eq ! (
1110+ Some ( prefix_len) ,
1111+ mask. into( ) . to_prefix_len( )
1112+ ) ;
1113+ }
1114+
1115+ test_eq ( 0 , Ipv4Address :: new ( 0 , 0 , 0 , 0 ) ) ;
1116+ test_eq ( 1 , Ipv4Address :: new ( 128 , 0 , 0 , 0 ) ) ;
1117+ test_eq ( 2 , Ipv4Address :: new ( 192 , 0 , 0 , 0 ) ) ;
1118+ test_eq ( 3 , Ipv4Address :: new ( 224 , 0 , 0 , 0 ) ) ;
1119+ test_eq ( 4 , Ipv4Address :: new ( 240 , 0 , 0 , 0 ) ) ;
1120+ test_eq ( 5 , Ipv4Address :: new ( 248 , 0 , 0 , 0 ) ) ;
1121+ test_eq ( 6 , Ipv4Address :: new ( 252 , 0 , 0 , 0 ) ) ;
1122+ test_eq ( 7 , Ipv4Address :: new ( 254 , 0 , 0 , 0 ) ) ;
1123+ test_eq ( 8 , Ipv4Address :: new ( 255 , 0 , 0 , 0 ) ) ;
1124+ test_eq ( 9 , Ipv4Address :: new ( 255 , 128 , 0 , 0 ) ) ;
1125+ test_eq ( 10 , Ipv4Address :: new ( 255 , 192 , 0 , 0 ) ) ;
1126+ test_eq ( 11 , Ipv4Address :: new ( 255 , 224 , 0 , 0 ) ) ;
1127+ test_eq ( 12 , Ipv4Address :: new ( 255 , 240 , 0 , 0 ) ) ;
1128+ test_eq ( 13 , Ipv4Address :: new ( 255 , 248 , 0 , 0 ) ) ;
1129+ test_eq ( 14 , Ipv4Address :: new ( 255 , 252 , 0 , 0 ) ) ;
1130+ test_eq ( 15 , Ipv4Address :: new ( 255 , 254 , 0 , 0 ) ) ;
1131+ test_eq ( 16 , Ipv4Address :: new ( 255 , 255 , 0 , 0 ) ) ;
1132+ test_eq ( 17 , Ipv4Address :: new ( 255 , 255 , 128 , 0 ) ) ;
1133+ test_eq ( 18 , Ipv4Address :: new ( 255 , 255 , 192 , 0 ) ) ;
1134+ test_eq ( 19 , Ipv4Address :: new ( 255 , 255 , 224 , 0 ) ) ;
1135+ test_eq ( 20 , Ipv4Address :: new ( 255 , 255 , 240 , 0 ) ) ;
1136+ test_eq ( 21 , Ipv4Address :: new ( 255 , 255 , 248 , 0 ) ) ;
1137+ test_eq ( 22 , Ipv4Address :: new ( 255 , 255 , 252 , 0 ) ) ;
1138+ test_eq ( 23 , Ipv4Address :: new ( 255 , 255 , 254 , 0 ) ) ;
1139+ test_eq ( 24 , Ipv4Address :: new ( 255 , 255 , 255 , 0 ) ) ;
1140+ test_eq ( 25 , Ipv4Address :: new ( 255 , 255 , 255 , 128 ) ) ;
1141+ test_eq ( 26 , Ipv4Address :: new ( 255 , 255 , 255 , 192 ) ) ;
1142+ test_eq ( 27 , Ipv4Address :: new ( 255 , 255 , 255 , 224 ) ) ;
1143+ test_eq ( 28 , Ipv4Address :: new ( 255 , 255 , 255 , 240 ) ) ;
1144+ test_eq ( 29 , Ipv4Address :: new ( 255 , 255 , 255 , 248 ) ) ;
1145+ test_eq ( 30 , Ipv4Address :: new ( 255 , 255 , 255 , 252 ) ) ;
1146+ test_eq ( 31 , Ipv4Address :: new ( 255 , 255 , 255 , 254 ) ) ;
1147+ test_eq ( 32 , Ipv4Address :: new ( 255 , 255 , 255 , 255 ) ) ;
1148+ }
1149+
1150+ #[ cfg( feature = "proto-ipv4" ) ]
1151+ fn to_prefix_len_ipv4_error ( ) {
1152+ assert_eq ! ( None , IpAddress :: from( Ipv4Address :: new( 255 , 255 , 255 , 1 ) ) . to_prefix_len( ) ) ;
1153+ }
1154+
1155+ #[ test]
1156+ #[ cfg( feature = "proto-ipv6" ) ]
1157+ fn to_prefix_len_ipv6 ( ) {
1158+ fn test_eq < A : Into < Address > > ( prefix_len : u8 , mask : A ) {
1159+ assert_eq ! (
1160+ Some ( prefix_len) ,
1161+ mask. into( ) . to_prefix_len( )
1162+ ) ;
1163+ }
1164+
1165+ test_eq ( 0 , Ipv6Address :: new ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ;
1166+ test_eq ( 128 , Ipv6Address :: new ( 0xffff , 0xffff , 0xffff , 0xffff , 0xffff , 0xffff , 0xffff , 0xffff ) ) ;
1167+ }
1168+
1169+ #[ cfg( feature = "proto-ipv6" ) ]
1170+ fn to_prefix_len_ipv6_error ( ) {
1171+ assert_eq ! ( None , IpAddress :: from( Ipv6Address :: new( 0xffff , 0xffff , 0xffff , 0xffff , 0xffff , 0xffff , 0 , 1 ) ) . to_prefix_len( ) ) ;
1172+ }
10771173}
0 commit comments