cidr_utils/separator/
v6.rs

1use std::cmp::Ordering;
2
3use cidr::Ipv6Cidr;
4use num_bigint::BigUint;
5use num_traits::{One, ToPrimitive};
6
7use crate::{combiner::Ipv6CidrCombiner, iterator::Ipv6CidrIpv6AddrIterator, Ipv6CidrSize};
8
9/// To divide an IPv6 CIDR into subnetworks.
10#[derive(Debug)]
11pub struct Ipv6CidrSeparator;
12
13impl Ipv6CidrSeparator {
14    /// Evenly divide an IPv6 CIDR into a specific number of subnetworks.
15    pub fn divide_by(cidr: &Ipv6Cidr, n: usize) -> Option<Vec<Ipv6CidrCombiner>> {
16        let size = cidr.size();
17
18        let n_big_int = BigUint::from(n);
19
20        if n == 0 || n_big_int > size {
21            return None;
22        } else if n == 1 {
23            let mut combiner = Ipv6CidrCombiner::with_capacity(1);
24
25            combiner.push(*cidr);
26
27            return Some(vec![combiner]);
28        }
29
30        let d = size.clone() / n_big_int.clone();
31
32        let mut output = Vec::with_capacity(n);
33
34        if d.clone() * n_big_int == size {
35            let mut iter = Ipv6CidrIpv6AddrIterator::new(cidr);
36
37            let bits = cidr.network_length() + n.ilog2() as u8;
38
39            let usize_max_big_int = BigUint::from(usize::MAX);
40
41            if d <= usize_max_big_int {
42                for ip in iter.step_by(d.to_usize().unwrap()) {
43                    let mut combiner = Ipv6CidrCombiner::with_capacity(1);
44
45                    combiner.push(Ipv6Cidr::new(ip, bits).unwrap());
46
47                    output.push(combiner);
48                }
49            } else {
50                let nth = d - BigUint::one();
51
52                if let Some(ip) = iter.next() {
53                    let mut combiner = Ipv6CidrCombiner::with_capacity(1);
54
55                    combiner.push(Ipv6Cidr::new(ip, bits).unwrap());
56
57                    output.push(combiner);
58
59                    while let Some(ip) = iter.nth_big_uint(nth.clone()) {
60                        let mut combiner = Ipv6CidrCombiner::with_capacity(1);
61
62                        combiner.push(Ipv6Cidr::new(ip, bits).unwrap());
63
64                        output.push(combiner);
65                    }
66                }
67            }
68        } else {
69            let iter = Ipv6CidrIpv6AddrIterator::new(cidr);
70
71            let mut current_combiner = Ipv6CidrCombiner::new();
72
73            let mut i = BigUint::one();
74
75            for ip in iter {
76                current_combiner.push(Ipv6Cidr::new(ip, 128).unwrap());
77
78                if i == d {
79                    output.push(current_combiner);
80
81                    current_combiner = Ipv6CidrCombiner::new();
82
83                    i = BigUint::one();
84                } else {
85                    i += BigUint::one();
86                }
87            }
88
89            let last_combiner = output.last_mut().unwrap();
90
91            for cidr in current_combiner.into_ipv6_cidr_vec().into_iter() {
92                last_combiner.push(cidr);
93            }
94        }
95
96        Some(output)
97    }
98
99    /// Divide an IPv6 CIDR into subnetworks with a specific bits.
100    pub fn sub_networks(cidr: &Ipv6Cidr, bits: u8) -> Option<Vec<Ipv6Cidr>> {
101        let cidr_bits = cidr.network_length();
102
103        match cidr_bits.cmp(&bits) {
104            Ordering::Greater => return None,
105            Ordering::Equal => return Some(vec![*cidr]),
106            Ordering::Less => (),
107        }
108
109        let n = 2usize.pow(u32::from(bits - cidr_bits));
110
111        let n_big_int = BigUint::from(n);
112
113        let mut output = Vec::with_capacity(n);
114
115        let size = cidr.size();
116
117        let d = size / n_big_int;
118
119        let mut iter = Ipv6CidrIpv6AddrIterator::new(cidr);
120
121        let usize_max_big_int = BigUint::from(usize::MAX);
122
123        if d <= usize_max_big_int {
124            for ip in iter.step_by(d.to_usize().unwrap()) {
125                output.push(Ipv6Cidr::new(ip, bits).unwrap());
126            }
127        } else {
128            let nth = d - BigUint::one();
129
130            if let Some(ip) = iter.next() {
131                output.push(Ipv6Cidr::new(ip, bits).unwrap());
132
133                while let Some(ip) = iter.nth_big_uint(nth.clone()) {
134                    output.push(Ipv6Cidr::new(ip, bits).unwrap());
135                }
136            }
137        }
138
139        Some(output)
140    }
141}