ip/any/prefix/
set.rs

1use core::cmp::Ordering;
2use core::ops::{Add, BitAnd, BitOr, BitXor, Mul, Not, Sub};
3
4use num_traits::{One, Zero};
5
6use super::{Prefix, Range};
7use crate::{
8    concrete::{self, Ipv4, Ipv6},
9    traits,
10};
11
12/// A collection of mixed IPv4 and IPv6 prefixes.
13///
14/// See also [`traits::PrefixSet`] and [`concrete::PrefixSet`].
15///
16/// # Examples
17///
18/// ```
19/// # use core::str::FromStr;
20/// # use ip::{Any, Error, Prefix, PrefixRange, PrefixSet, traits::PrefixSet as _};
21/// let set: PrefixSet<Any> = ["192.0.2.0/24,25,26", "2001:db8::/48,52,52"]
22///     .into_iter()
23///     .map(PrefixRange::<Any>::from_str)
24///     .collect::<Result<_, _>>()?;
25/// assert_eq!(set.len(), 6 + 16);
26/// # Ok::<_, Error>(())
27/// ```
28#[derive(Clone, Debug, Default, PartialEq, Eq)]
29pub struct Set {
30    ipv4: concrete::PrefixSet<Ipv4>,
31    ipv6: concrete::PrefixSet<Ipv6>,
32}
33
34impl Set {
35    fn aggregate(&mut self) -> &mut Self {
36        _ = self.ipv4.aggregate();
37        _ = self.ipv6.aggregate();
38        self
39    }
40
41    /// Partition the prefix set by address family.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// # use core::str::FromStr;
47    /// # use ip::{Any, Error, Prefix, PrefixSet, traits::PrefixSet as _};
48    /// let set: PrefixSet<Any> = ["192.0.2.0/24", "2001:db8::/32"]
49    ///     .into_iter()
50    ///     .map(Prefix::<Any>::from_str)
51    ///     .collect::<Result<_, _>>()?;
52    /// let (_, ipv6) = set.partition();
53    /// let mut ipv6_prefixes = ipv6.prefixes();
54    /// assert_eq!(
55    ///     ipv6_prefixes.next().map(|p| p.to_string()),
56    ///     Some("2001:db8::/32".to_string())
57    /// );
58    /// assert_eq!(ipv6_prefixes.next(), None);
59    /// # Ok::<_, Error>(())
60    /// ```
61    #[must_use]
62    #[allow(clippy::missing_const_for_fn)]
63    pub fn partition(self) -> (concrete::PrefixSet<Ipv4>, concrete::PrefixSet<Ipv6>) {
64        (self.ipv4, self.ipv6)
65    }
66
67    /// Borrow the address-family partitions of the prefix set.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// # use core::str::FromStr;
73    /// # use ip::{Any, Error, Prefix, PrefixSet, traits::PrefixSet as _};
74    /// let set: PrefixSet<Any> = ["192.0.2.0/24", "2001:db8::/32"]
75    ///     .into_iter()
76    ///     .map(Prefix::<Any>::from_str)
77    ///     .collect::<Result<_, _>>()?;
78    /// let (ipv4, _) = set.as_partitions();
79    /// let mut ipv4_prefixes = ipv4.prefixes();
80    /// assert_eq!(
81    ///     ipv4_prefixes.next().map(|p| p.to_string()),
82    ///     Some("192.0.2.0/24".to_string())
83    /// );
84    /// assert_eq!(ipv4_prefixes.next(), None);
85    /// # Ok::<_, Error>(())
86    /// ```
87    #[must_use]
88    pub const fn as_partitions(&self) -> (&concrete::PrefixSet<Ipv4>, &concrete::PrefixSet<Ipv6>) {
89        (&self.ipv4, &self.ipv6)
90    }
91
92    /// Mutably borrow the address-family partitions of the prefix set.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// # use core::str::FromStr;
98    /// # use ip::{Any, Ipv4, Error, Prefix, PrefixSet, traits::PrefixSet as _};
99    /// let mut set: PrefixSet<Any> = ["192.0.2.0/24", "2001:db8::/32"]
100    ///     .into_iter()
101    ///     .map(Prefix::<Any>::from_str)
102    ///     .collect::<Result<_, _>>()?;
103    ///
104    /// let (ipv4, _) = set.as_mut_partitions();
105    /// let new = "192.0.2.128/25".parse::<Prefix<Ipv4>>()?;
106    /// _ = ipv4.insert(new);
107    ///
108    /// assert_eq!(set.len(), 3);
109    /// # Ok::<_, Error>(())
110    /// ```
111    #[must_use]
112    pub fn as_mut_partitions(
113        &mut self,
114    ) -> (
115        &mut concrete::PrefixSet<Ipv4>,
116        &mut concrete::PrefixSet<Ipv6>,
117    ) {
118        (&mut self.ipv4, &mut self.ipv6)
119    }
120}
121
122#[derive(Debug)]
123pub struct Prefixes<'a> {
124    ipv4: <concrete::PrefixSet<Ipv4> as traits::PrefixSet<'a>>::Prefixes,
125    ipv6: <concrete::PrefixSet<Ipv6> as traits::PrefixSet<'a>>::Prefixes,
126}
127
128impl Iterator for Prefixes<'_> {
129    type Item = Prefix;
130
131    fn next(&mut self) -> Option<Self::Item> {
132        self.ipv4
133            .next()
134            .map(Prefix::Ipv4)
135            .or_else(|| self.ipv6.next().map(Prefix::Ipv6))
136    }
137}
138
139#[derive(Debug)]
140pub struct Ranges<'a> {
141    ipv4: <concrete::PrefixSet<Ipv4> as traits::PrefixSet<'a>>::Ranges,
142    ipv6: <concrete::PrefixSet<Ipv6> as traits::PrefixSet<'a>>::Ranges,
143}
144
145impl Iterator for Ranges<'_> {
146    type Item = Range;
147
148    fn next(&mut self) -> Option<Self::Item> {
149        self.ipv4
150            .next()
151            .map(Self::Item::Ipv4)
152            .or_else(|| self.ipv6.next().map(Self::Item::Ipv6))
153    }
154}
155
156impl<'a> traits::PrefixSet<'a> for Set {
157    type Prefix = Prefix;
158    type Range = Range;
159    type Prefixes = Prefixes<'a>;
160    type Ranges = Ranges<'a>;
161
162    fn prefixes(&'a self) -> Self::Prefixes {
163        Self::Prefixes {
164            ipv4: self.ipv4.prefixes(),
165            ipv6: self.ipv6.prefixes(),
166        }
167    }
168
169    fn ranges(&'a self) -> Self::Ranges {
170        Self::Ranges {
171            ipv4: self.ipv4.ranges(),
172            ipv6: self.ipv6.ranges(),
173        }
174    }
175
176    fn contains(&self, prefix: Self::Prefix) -> bool {
177        match prefix {
178            Self::Prefix::Ipv4(prefix) => self.ipv4.contains(prefix),
179            Self::Prefix::Ipv6(prefix) => self.ipv6.contains(prefix),
180        }
181    }
182}
183
184impl From<concrete::PrefixSet<Ipv4>> for Set {
185    fn from(value: concrete::PrefixSet<Ipv4>) -> Self {
186        Self {
187            ipv4: value,
188            ..Default::default()
189        }
190    }
191}
192
193impl From<concrete::PrefixSet<Ipv6>> for Set {
194    fn from(value: concrete::PrefixSet<Ipv6>) -> Self {
195        Self {
196            ipv6: value,
197            ..Default::default()
198        }
199    }
200}
201
202impl Extend<Prefix> for Set {
203    #[allow(unused_results)]
204    fn extend<I>(&mut self, iter: I)
205    where
206        I: IntoIterator<Item = Prefix>,
207    {
208        iter.into_iter().for_each(|prefix| match prefix {
209            Prefix::Ipv4(prefix) => {
210                self.ipv4.insert_only(prefix);
211            }
212            Prefix::Ipv6(prefix) => {
213                self.ipv6.insert_only(prefix);
214            }
215        });
216        self.aggregate();
217    }
218}
219
220impl Extend<Range> for Set {
221    #[allow(unused_results)]
222    fn extend<I>(&mut self, iter: I)
223    where
224        I: IntoIterator<Item = Range>,
225    {
226        iter.into_iter().for_each(|range| match range {
227            Range::Ipv4(range) => {
228                self.ipv4.insert_only(range);
229            }
230            Range::Ipv6(range) => {
231                self.ipv6.insert_only(range);
232            }
233        });
234        self.aggregate();
235    }
236}
237
238impl<T> FromIterator<T> for Set
239where
240    Self: Extend<T>,
241{
242    fn from_iter<I>(iter: I) -> Self
243    where
244        I: IntoIterator<Item = T>,
245    {
246        let mut this = Self::default();
247        this.extend(iter);
248        this
249    }
250}
251
252impl One for Set {
253    fn one() -> Self {
254        Self {
255            ipv4: concrete::PrefixSet::one(),
256            ipv6: concrete::PrefixSet::one(),
257        }
258    }
259}
260
261impl Zero for Set {
262    fn zero() -> Self {
263        Self {
264            ipv4: concrete::PrefixSet::zero(),
265            ipv6: concrete::PrefixSet::zero(),
266        }
267    }
268
269    fn is_zero(&self) -> bool {
270        self == &Self::zero()
271    }
272}
273
274impl BitAnd for Set {
275    type Output = Self;
276
277    fn bitand(self, rhs: Self) -> Self::Output {
278        Self {
279            ipv4: self.ipv4 & rhs.ipv4,
280            ipv6: self.ipv6 & rhs.ipv6,
281        }
282    }
283}
284
285impl BitOr for Set {
286    type Output = Self;
287
288    fn bitor(self, rhs: Self) -> Self::Output {
289        Self {
290            ipv4: self.ipv4 | rhs.ipv4,
291            ipv6: self.ipv6 | rhs.ipv6,
292        }
293    }
294}
295
296impl BitXor for Set {
297    type Output = Self;
298
299    fn bitxor(self, rhs: Self) -> Self::Output {
300        Self {
301            ipv4: self.ipv4 ^ rhs.ipv4,
302            ipv6: self.ipv6 ^ rhs.ipv6,
303        }
304    }
305}
306
307impl Not for Set {
308    type Output = Self;
309
310    fn not(self) -> Self::Output {
311        Self {
312            ipv4: !self.ipv4,
313            ipv6: !self.ipv6,
314        }
315    }
316}
317
318impl Add for Set {
319    type Output = Self;
320
321    fn add(self, rhs: Self) -> Self::Output {
322        Self {
323            ipv4: self.ipv4 + rhs.ipv4,
324            ipv6: self.ipv6 + rhs.ipv6,
325        }
326    }
327}
328
329impl Mul for Set {
330    type Output = Self;
331
332    fn mul(self, rhs: Self) -> Self::Output {
333        Self {
334            ipv4: self.ipv4 * rhs.ipv4,
335            ipv6: self.ipv6 * rhs.ipv6,
336        }
337    }
338}
339
340impl Sub for Set {
341    type Output = Self;
342
343    fn sub(self, rhs: Self) -> Self::Output {
344        Self {
345            ipv4: self.ipv4 - rhs.ipv4,
346            ipv6: self.ipv6 - rhs.ipv6,
347        }
348    }
349}
350
351impl PartialOrd for Set {
352    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
353        use Ordering::{Equal, Greater, Less};
354        match (
355            self.ipv4.partial_cmp(&other.ipv4),
356            self.ipv6.partial_cmp(&other.ipv6),
357        ) {
358            (Some(ord4), Some(ord6)) => match (ord4, ord6) {
359                (Equal, Equal) => Some(Equal),
360                (Less | Equal, Less | Equal) => Some(Less),
361                (Greater | Equal, Greater | Equal) => Some(Greater),
362                _ => None,
363            },
364            _ => None,
365        }
366    }
367}