use crate::*;
use ipnet::{Ipv4Net, Ipv6Net};
use std::cmp::Ordering;
use std::net::{Ipv4Addr, Ipv6Addr};
#[doc(hidden)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum IpPrefixCoverage {
NoCover,
WiderRange,
SameRange,
}
impl IpPrefixCoverage {
#[inline]
fn is_wider(&self) -> bool {
*self == IpPrefixCoverage::WiderRange
}
#[inline]
fn is_same(&self) -> bool {
*self == IpPrefixCoverage::SameRange
}
#[inline]
fn is_covering(&self) -> bool {
*self != IpPrefixCoverage::NoCover
}
}
pub trait IpPrefixCovering<P> {
#[doc(hidden)]
fn covering(&self, other: &P) -> IpPrefixCoverage;
#[inline]
fn covers(&self, other: &P) -> bool {
self.covering(other).is_covering()
}
#[inline]
#[doc(hidden)]
fn covers_striclty(&self, other: &P) -> bool {
self.covering(other).is_wider()
}
#[inline]
#[doc(hidden)]
fn covers_equally(&self, other: &P) -> bool {
self.covering(other).is_same()
}
}
impl<P: IpPrefix> IpPrefixCovering<Self> for P {
#[inline]
fn covering(&self, other: &Self) -> IpPrefixCoverage {
if other.bitslot() & self.bitmask() != self.bitslot_trunc() {
IpPrefixCoverage::NoCover
} else {
match self.len().cmp(&other.len()) {
Ordering::Less => IpPrefixCoverage::WiderRange,
Ordering::Equal => IpPrefixCoverage::SameRange,
Ordering::Greater => IpPrefixCoverage::NoCover,
}
}
}
}
macro_rules! ipcover {
($self:ty, $other:ty) => {
impl IpPrefixCovering<$other> for $self {
#[inline]
fn covering(&self, other: &$other) -> IpPrefixCoverage {
if other.bitslot() & self.bitmask() != self.bitslot_trunc() {
IpPrefixCoverage::NoCover
} else {
match self.len().cmp(&other.len()) {
Ordering::Less => IpPrefixCoverage::WiderRange,
Ordering::Equal => IpPrefixCoverage::SameRange,
Ordering::Greater => IpPrefixCoverage::NoCover,
}
}
}
}
};
}
ipcover!(Ipv4Prefix, Ipv4Net);
ipcover!(Ipv4Prefix, Ipv4Addr);
ipcover!(Ipv4Net, Ipv4Prefix);
ipcover!(Ipv4Net, Ipv4Addr);
ipcover!(Ipv6Prefix, Ipv6Net);
ipcover!(Ipv6Prefix, Ipv6Addr);
ipcover!(Ipv6Net, Ipv6Prefix);
ipcover!(Ipv6Net, Ipv6Addr);
macro_rules! ipcover_for_ipv6_on_u64 {
($short:ty, $other:ty) => {
impl IpPrefixCovering<$other> for $short {
#[inline]
fn covering(&self, other: &$other) -> IpPrefixCoverage {
if ((other.bitslot() >> 64) as u64) & self.bitmask() != self.bitslot_trunc() {
IpPrefixCoverage::NoCover
} else {
match self.len().cmp(&other.len()) {
Ordering::Less => IpPrefixCoverage::WiderRange,
Ordering::Equal => IpPrefixCoverage::SameRange,
Ordering::Greater => IpPrefixCoverage::NoCover,
}
}
}
}
};
}
ipcover_for_ipv6_on_u64!(Ipv6NetPrefix, Ipv6Prefix);
ipcover_for_ipv6_on_u64!(Ipv6NetPrefix, Ipv6Net);
ipcover_for_ipv6_on_u64!(Ipv6NetPrefix, Ipv6Addr);
macro_rules! ipcover_of_ipv6_on_u64 {
($self:ty, $short:ty) => {
impl IpPrefixCovering<$short> for $self {
#[inline]
fn covering(&self, other: &$short) -> IpPrefixCoverage {
if ((other.bitslot() as u128) << 64) & self.bitmask() != self.bitslot_trunc() {
IpPrefixCoverage::NoCover
} else {
match self.len().cmp(&other.len()) {
Ordering::Less => IpPrefixCoverage::WiderRange,
Ordering::Equal => IpPrefixCoverage::SameRange,
Ordering::Greater => IpPrefixCoverage::NoCover,
}
}
}
}
};
}
ipcover_of_ipv6_on_u64!(Ipv6Prefix, Ipv6NetPrefix);
ipcover_of_ipv6_on_u64!(Ipv6Net, Ipv6NetPrefix);
macro_rules! ipprefix_eq {
($self:ty, $other:ty) => {
impl PartialEq<$other> for $self {
#[inline]
fn eq(&self, other: &$other) -> bool {
self.covers_equally(other)
}
}
};
}
ipprefix_eq!(Ipv6Net, Ipv6NetPrefix);
ipprefix_eq!(Ipv6Net, Ipv6Prefix);
ipprefix_eq!(Ipv6NetPrefix, Ipv6Net);
ipprefix_eq!(Ipv6NetPrefix, Ipv6Prefix);
ipprefix_eq!(Ipv6Prefix, Ipv6Net);
ipprefix_eq!(Ipv6Prefix, Ipv6NetPrefix);