Skip to main content

iptrie/prefix/
cover.rs

1use crate::*;
2use ipnet::{Ipv4Net, Ipv6Net};
3use std::cmp::Ordering;
4use std::net::{Ipv4Addr, Ipv6Addr};
5
6#[doc(hidden)]
7#[derive(Copy, Clone, PartialEq, Eq, Debug)]
8pub enum IpPrefixCoverage {
9    NoCover,
10    WiderRange,
11    SameRange,
12}
13
14impl IpPrefixCoverage {
15    #[inline]
16    fn is_wider(&self) -> bool {
17        *self == IpPrefixCoverage::WiderRange
18    }
19    #[inline]
20    fn is_same(&self) -> bool {
21        *self == IpPrefixCoverage::SameRange
22    }
23    #[inline]
24    fn is_covering(&self) -> bool {
25        *self != IpPrefixCoverage::NoCover
26    }
27}
28
29/// A trait to check the prefix coverage
30pub trait IpPrefixCovering<P> {
31    /// Checks the coverage of this prefix against a set of adress
32    ///
33    /// * `SameRange` means that the two prefixes are equivalent
34    /// * `WiderRange` means that this prefix includes the other
35    /// * `NoCover` groups all the other cases
36    ///
37    /// # Difference with `PartialEq`
38    /// Two prefixes could be different but equivalent regarding to
39    /// the range of addresses they cover.
40    /// ```
41    /// # use iptrie::*;
42    /// use ipnet::Ipv4Net;
43    /// let a = "1.1.1.1/16".parse::<Ipv4Net>().unwrap();
44    /// let b = "1.1.2.2/16".parse::<Ipv4Net>().unwrap();
45    /// assert!( a != b ); // since host addr are different
46    /// assert! (a.covers_equally(&b) ); // but prefixes are equivalent
47    /// ```
48    #[doc(hidden)]
49    fn covering(&self, other: &P) -> IpPrefixCoverage;
50
51    /// Checks the coverage of this prefix against a set of addresses
52    ///
53    /// # Difference with `PartialEq`
54    /// Two prefixes could be different but equivalent regarding to
55    /// the range of addresses they cover.
56    /// ```
57    /// # use iptrie::*;
58    /// use ipnet::Ipv4Net;
59    /// let a = "1.1.1.1/16".parse::<Ipv4Net>().unwrap();
60    /// let b = "1.1.2.2/16".parse::<Ipv4Net>().unwrap();
61    /// assert!( a != b ); // host addr are different
62    /// assert! (a.covers(&b) && b.covers(&a)); // but prefixes are equivalent
63    /// ```
64    #[inline]
65    fn covers(&self, other: &P) -> bool {
66        self.covering(other).is_covering()
67    }
68
69    #[inline]
70    #[doc(hidden)]
71    fn covers_striclty(&self, other: &P) -> bool {
72        self.covering(other).is_wider()
73    }
74    #[inline]
75    #[doc(hidden)]
76    fn covers_equally(&self, other: &P) -> bool {
77        self.covering(other).is_same()
78    }
79}
80
81impl<P: IpPrefix> IpPrefixCovering<Self> for P {
82    #[inline]
83    fn covering(&self, other: &Self) -> IpPrefixCoverage {
84        if other.bitslot() & self.bitmask() != self.bitslot_trunc() {
85            IpPrefixCoverage::NoCover
86        } else {
87            match self.len().cmp(&other.len()) {
88                Ordering::Less => IpPrefixCoverage::WiderRange,
89                Ordering::Equal => IpPrefixCoverage::SameRange,
90                Ordering::Greater => IpPrefixCoverage::NoCover,
91            }
92        }
93    }
94}
95
96// coverage impl. between prefixes with same slots and same addr type
97macro_rules! ipcover {
98    ($self:ty, $other:ty) => {
99        impl IpPrefixCovering<$other> for $self {
100            #[inline]
101            fn covering(&self, other: &$other) -> IpPrefixCoverage {
102                if other.bitslot() & self.bitmask() != self.bitslot_trunc() {
103                    IpPrefixCoverage::NoCover
104                } else {
105                    match self.len().cmp(&other.len()) {
106                        Ordering::Less => IpPrefixCoverage::WiderRange,
107                        Ordering::Equal => IpPrefixCoverage::SameRange,
108                        Ordering::Greater => IpPrefixCoverage::NoCover,
109                    }
110                }
111            }
112        }
113    };
114}
115
116ipcover!(Ipv4Prefix, Ipv4Net);
117ipcover!(Ipv4Prefix, Ipv4Addr);
118
119ipcover!(Ipv4Net, Ipv4Prefix);
120ipcover!(Ipv4Net, Ipv4Addr);
121
122ipcover!(Ipv6Prefix, Ipv6Net);
123ipcover!(Ipv6Prefix, Ipv6Addr);
124
125ipcover!(Ipv6Net, Ipv6Prefix);
126ipcover!(Ipv6Net, Ipv6Addr);
127
128// coverage impl. relative to IpPrefix56 or IpNetAddr
129// (which has a slot shorter than the others)
130macro_rules! ipcover_for_ipv6_on_u64 {
131    ($short:ty, $other:ty) => {
132        impl IpPrefixCovering<$other> for $short {
133            #[inline]
134            fn covering(&self, other: &$other) -> IpPrefixCoverage {
135                if ((other.bitslot() >> 64) as u64) & self.bitmask() != self.bitslot_trunc() {
136                    IpPrefixCoverage::NoCover
137                } else {
138                    match self.len().cmp(&other.len()) {
139                        Ordering::Less => IpPrefixCoverage::WiderRange,
140                        Ordering::Equal => IpPrefixCoverage::SameRange,
141                        Ordering::Greater => IpPrefixCoverage::NoCover,
142                    }
143                }
144            }
145        }
146    };
147}
148
149ipcover_for_ipv6_on_u64!(Ipv6NetPrefix, Ipv6Prefix);
150ipcover_for_ipv6_on_u64!(Ipv6NetPrefix, Ipv6Net);
151ipcover_for_ipv6_on_u64!(Ipv6NetPrefix, Ipv6Addr);
152
153macro_rules! ipcover_of_ipv6_on_u64 {
154    ($self:ty, $short:ty) => {
155        impl IpPrefixCovering<$short> for $self {
156            #[inline]
157            fn covering(&self, other: &$short) -> IpPrefixCoverage {
158                if ((other.bitslot() as u128) << 64) & self.bitmask() != self.bitslot_trunc() {
159                    IpPrefixCoverage::NoCover
160                } else {
161                    match self.len().cmp(&other.len()) {
162                        Ordering::Less => IpPrefixCoverage::WiderRange,
163                        Ordering::Equal => IpPrefixCoverage::SameRange,
164                        Ordering::Greater => IpPrefixCoverage::NoCover,
165                    }
166                }
167            }
168        }
169    };
170}
171
172ipcover_of_ipv6_on_u64!(Ipv6Prefix, Ipv6NetPrefix);
173ipcover_of_ipv6_on_u64!(Ipv6Net, Ipv6NetPrefix);
174
175// Equality between prefix...
176macro_rules! ipprefix_eq {
177    ($self:ty, $other:ty) => {
178        impl PartialEq<$other> for $self {
179            #[inline]
180            fn eq(&self, other: &$other) -> bool {
181                self.covers_equally(other)
182            }
183        }
184    };
185}
186
187ipprefix_eq!(Ipv6Net, Ipv6NetPrefix);
188ipprefix_eq!(Ipv6Net, Ipv6Prefix);
189
190ipprefix_eq!(Ipv6NetPrefix, Ipv6Net);
191ipprefix_eq!(Ipv6NetPrefix, Ipv6Prefix);
192
193ipprefix_eq!(Ipv6Prefix, Ipv6Net);
194ipprefix_eq!(Ipv6Prefix, Ipv6NetPrefix);