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