mirror of
https://github.com/achanda/ipnetwork.git
synced 2025-06-16 16:58:50 +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`.
|
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
|
||||||
pub fn ipv4_mask_to_prefix(mask: Ipv4Addr) -> Result<u8, IpNetworkError> {
|
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;
|
let prefix = (!mask).leading_zeros() as u8;
|
||||||
if (u64::from(mask) << prefix) & 0xffff_ffff != 0 {
|
if ((mask as u64) << prefix) & 0xffff_ffff != 0 {
|
||||||
Err(IpNetworkError::InvalidPrefix)
|
None
|
||||||
} else {
|
} 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.
|
/// Converts a `Ipv6Addr` network mask into a prefix.
|
||||||
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
|
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
|
||||||
pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, IpNetworkError> {
|
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 mask = mask.segments();
|
||||||
let mut mask_iter = mask.iter();
|
|
||||||
|
|
||||||
// Count the number of set bits from the start of the address
|
// Count the number of set bits from the start of the address
|
||||||
let mut prefix = 0;
|
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 {
|
if segment == 0xffff {
|
||||||
prefix += IPV6_SEGMENT_BITS;
|
prefix += IPV6_SEGMENT_BITS;
|
||||||
} else if segment == 0 {
|
} 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;
|
let prefix_bits = (!segment).leading_zeros() as u8;
|
||||||
// Check that the remainder of the bits are all unset
|
// Check that the remainder of the bits are all unset
|
||||||
if segment << prefix_bits != 0 {
|
if segment << prefix_bits != 0 {
|
||||||
return Err(IpNetworkError::InvalidPrefix);
|
return None;
|
||||||
}
|
}
|
||||||
prefix += prefix_bits;
|
prefix += prefix_bits;
|
||||||
break;
|
break;
|
||||||
@ -414,13 +427,15 @@ pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, IpNetworkError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now check all the remaining bits are unset
|
// 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 {
|
if segment != 0 {
|
||||||
return Err(IpNetworkError::InvalidPrefix);
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(prefix)
|
Some(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
17
src/lib.rs
17
src/lib.rs
@ -16,11 +16,11 @@ mod ipv6;
|
|||||||
mod parse;
|
mod parse;
|
||||||
mod size;
|
mod size;
|
||||||
|
|
||||||
pub use crate::error::{NetworkSizeError, IpNetworkError};
|
pub use crate::error::{IpNetworkError, NetworkSizeError};
|
||||||
pub use crate::ipv4::Ipv4NetworkIterator;
|
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::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;
|
pub use crate::size::NetworkSize;
|
||||||
|
|
||||||
/// Represents a generic network range. This type can have two variants:
|
/// 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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
#[test]
|
#[test]
|
||||||
|
Reference in New Issue
Block a user