mirror of
https://github.com/achanda/ipnetwork.git
synced 2025-06-15 00:26:33 +00:00
Add ip_mask_to_prefix_checked
(#214)
* Add `ipv4_mask_to_prefix_checked` * Add `ipv6_mask_to_prefix_checked` * Add `ip_mask_to_prefix_checked`
This commit is contained in:

committed by
GitHub

parent
170fc4ca6b
commit
0deb2abd8b
19
src/ipv4.rs
19
src/ipv4.rs
@ -382,13 +382,24 @@ impl IntoIterator for &'_ Ipv4Network {
|
||||
///
|
||||
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
|
||||
pub fn ipv4_mask_to_prefix(mask: Ipv4Addr) -> Result<u8, IpNetworkError> {
|
||||
let mask = u32::from(mask);
|
||||
match ipv4_mask_to_prefix_checked(mask) {
|
||||
Some(prefix) => Ok(prefix),
|
||||
None => Err(IpNetworkError::InvalidPrefix),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `Ipv4Addr` network mask into a prefix.
|
||||
///
|
||||
/// If the mask is invalid this will return `None`. This is useful in const contexts where
|
||||
/// [`Option::unwrap`] may be called to trigger a compile-time error if the prefix is invalid.
|
||||
pub const fn ipv4_mask_to_prefix_checked(mask: Ipv4Addr) -> Option<u8> {
|
||||
let mask = mask.to_bits();
|
||||
|
||||
let prefix = (!mask).leading_zeros() as u8;
|
||||
if (u64::from(mask) << prefix) & 0xffff_ffff != 0 {
|
||||
Err(IpNetworkError::InvalidPrefix)
|
||||
if ((mask as u64) << prefix) & 0xffff_ffff != 0 {
|
||||
None
|
||||
} else {
|
||||
Ok(prefix)
|
||||
Some(prefix)
|
||||
}
|
||||
}
|
||||
|
||||
|
27
src/ipv6.rs
27
src/ipv6.rs
@ -391,12 +391,25 @@ impl fmt::Display for Ipv6Network {
|
||||
/// Converts a `Ipv6Addr` network mask into a prefix.
|
||||
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
|
||||
pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, IpNetworkError> {
|
||||
match ipv6_mask_to_prefix_checked(mask) {
|
||||
Some(prefix) => Ok(prefix),
|
||||
None => Err(IpNetworkError::InvalidPrefix),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `Ipv6Addr` network mask into a prefix.
|
||||
///
|
||||
/// If the mask is invalid this will return `None`. This is useful in const contexts where
|
||||
/// [`Option::unwrap`] may be called to trigger a compile-time error if the prefix is invalid.
|
||||
pub const fn ipv6_mask_to_prefix_checked(mask: Ipv6Addr) -> Option<u8> {
|
||||
let mask = mask.segments();
|
||||
let mut mask_iter = mask.iter();
|
||||
|
||||
// Count the number of set bits from the start of the address
|
||||
let mut prefix = 0;
|
||||
for &segment in &mut mask_iter {
|
||||
let mut i = 0;
|
||||
while i < mask.len() {
|
||||
let segment = mask[i];
|
||||
i += 1;
|
||||
if segment == 0xffff {
|
||||
prefix += IPV6_SEGMENT_BITS;
|
||||
} else if segment == 0 {
|
||||
@ -406,7 +419,7 @@ pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, IpNetworkError> {
|
||||
let prefix_bits = (!segment).leading_zeros() as u8;
|
||||
// Check that the remainder of the bits are all unset
|
||||
if segment << prefix_bits != 0 {
|
||||
return Err(IpNetworkError::InvalidPrefix);
|
||||
return None;
|
||||
}
|
||||
prefix += prefix_bits;
|
||||
break;
|
||||
@ -414,13 +427,15 @@ pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, IpNetworkError> {
|
||||
}
|
||||
|
||||
// Now check all the remaining bits are unset
|
||||
for &segment in mask_iter {
|
||||
while i < mask.len() {
|
||||
let segment = mask[i];
|
||||
i += 1;
|
||||
if segment != 0 {
|
||||
return Err(IpNetworkError::InvalidPrefix);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(prefix)
|
||||
Some(prefix)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
17
src/lib.rs
17
src/lib.rs
@ -16,11 +16,11 @@ mod ipv6;
|
||||
mod parse;
|
||||
mod size;
|
||||
|
||||
pub use crate::error::{NetworkSizeError, IpNetworkError};
|
||||
pub use crate::error::{IpNetworkError, NetworkSizeError};
|
||||
pub use crate::ipv4::Ipv4NetworkIterator;
|
||||
pub use crate::ipv4::{ipv4_mask_to_prefix, Ipv4Network};
|
||||
pub use crate::ipv4::{ipv4_mask_to_prefix, ipv4_mask_to_prefix_checked, Ipv4Network};
|
||||
pub use crate::ipv6::Ipv6NetworkIterator;
|
||||
pub use crate::ipv6::{ipv6_mask_to_prefix, Ipv6Network};
|
||||
pub use crate::ipv6::{ipv6_mask_to_prefix, ipv6_mask_to_prefix_checked, Ipv6Network};
|
||||
pub use crate::size::NetworkSize;
|
||||
|
||||
/// Represents a generic network range. This type can have two variants:
|
||||
@ -433,6 +433,17 @@ pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `IpAddr` network mask into a prefix.
|
||||
///
|
||||
/// If the mask is invalid this will return `None`. This is useful in const contexts where
|
||||
/// [`Option::unwrap`] may be called to trigger a compile-time error if the prefix is invalid.
|
||||
pub const fn ip_mask_to_prefix_checked(mask: IpAddr) -> Option<u8> {
|
||||
match mask {
|
||||
IpAddr::V4(mask) => ipv4_mask_to_prefix_checked(mask),
|
||||
IpAddr::V6(mask) => ipv6_mask_to_prefix_checked(mask),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
|
Reference in New Issue
Block a user