ip/concrete/prefix/
subprefixes.rs

1use super::{Bitmask, Hostmask, Netmask, Prefix, PrefixLength};
2use crate::{
3    error::{err, Error, Kind},
4    traits::{Afi, Prefix as _, PrefixLength as _},
5};
6
7/// Iterator returned by [`Prefix::subprefixes`].
8#[derive(Debug, Clone)]
9pub struct Subprefixes<A: Afi> {
10    base: Prefix<A>,
11    next: Option<Prefix<A>>,
12    step: Option<Bitmask<A>>,
13}
14
15impl<A: Afi> Subprefixes<A> {
16    pub(super) fn new(base: Prefix<A>, length: PrefixLength<A>) -> Result<Self, Error> {
17        if length < base.length() {
18            Err(err!(Kind::PrefixLength))
19        } else {
20            let next = Some(Prefix::new(base.prefix(), length));
21            let step = length
22                .decrement()
23                .map(Hostmask::from)
24                .map(|hostbits| hostbits & Netmask::from(length))
25                .ok();
26            Ok(Self { base, next, step })
27        }
28    }
29}
30
31impl<A: Afi> Iterator for Subprefixes<A> {
32    type Item = Prefix<A>;
33
34    fn next(&mut self) -> Option<Self::Item> {
35        if let Some(next) = self.next.take() {
36            self.next = self
37                .step
38                .and_then(|step| next.map_addr(|addr| addr + step))
39                .filter(|prefix| self.base.contains(prefix));
40            Some(next)
41        } else {
42            None
43        }
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use crate::{traits::Prefix as _, Any, Ipv4, Ipv6, Prefix};
50
51    #[test]
52    fn singleton_subprefix_ipv4() {
53        let p: Prefix<Ipv4> = "192.0.2.0/24".parse().unwrap();
54        let mut subprefixes = p.subprefixes(p.prefix_len()).unwrap();
55        assert_eq!(subprefixes.next(), Some(p));
56        assert_eq!(subprefixes.next(), None);
57    }
58
59    #[test]
60    fn singleton_subprefix_ipv6() {
61        let p: Prefix<Ipv6> = "2001:db8::/48".parse().unwrap();
62        let mut subprefixes = p.subprefixes(p.prefix_len()).unwrap();
63        assert_eq!(subprefixes.next(), Some(p));
64        assert_eq!(subprefixes.next(), None);
65    }
66
67    #[test]
68    fn singleton_subprefix_any() {
69        let p: Prefix<Any> = "2001:db8:f00::/64".parse().unwrap();
70        let mut subprefixes = p.subprefixes(p.prefix_len()).unwrap();
71        assert_eq!(subprefixes.next(), Some(p));
72        assert_eq!(subprefixes.next(), None);
73    }
74
75    #[test]
76    fn count_subprefixes_of_default() {
77        let p: Prefix<Ipv4> = "0.0.0.0/0".parse().unwrap();
78        let len = p.new_prefix_length(8).unwrap();
79        assert_eq!(p.subprefixes(len).unwrap().count(), 256);
80    }
81}