cidr_utils/combiner/
v4.rs1use core::ops::Deref;
2use std::net::Ipv4Addr;
3
4use cidr::Ipv4Cidr;
5
6use crate::Ipv4CidrSize;
7
8#[derive(Debug, Clone)]
10pub struct Ipv4CidrCombiner(Vec<Ipv4Cidr>);
11
12impl Default for Ipv4CidrCombiner {
13 #[inline]
14 fn default() -> Self {
15 Ipv4CidrCombiner::new()
16 }
17}
18
19impl Deref for Ipv4CidrCombiner {
20 type Target = Vec<Ipv4Cidr>;
21
22 #[inline]
23 fn deref(&self) -> &Vec<Ipv4Cidr> {
24 &self.0
25 }
26}
27
28impl Ipv4CidrCombiner {
29 #[inline]
31 pub const fn new() -> Ipv4CidrCombiner {
32 Ipv4CidrCombiner(Vec::new())
33 }
34
35 #[inline]
37 pub fn with_capacity(capacity: usize) -> Ipv4CidrCombiner {
38 Ipv4CidrCombiner(Vec::with_capacity(capacity))
39 }
40
41 #[inline]
47 pub const unsafe fn from_ipv4_cidr_vec_unchecked(cidr_vec: Vec<Ipv4Cidr>) -> Ipv4CidrCombiner {
48 Ipv4CidrCombiner(cidr_vec)
49 }
50
51 #[inline]
52 pub fn into_ipv4_cidr_vec(self) -> Vec<Ipv4Cidr> {
53 self.0
54 }
55}
56
57impl Ipv4CidrCombiner {
58 pub fn push(&mut self, mut cidr: Ipv4Cidr) {
60 if let Err(mut index) = self.0.binary_search(&cidr) {
61 if self.0.is_empty() {
62 self.0.push(cidr);
63 } else {
64 let pushable = if index == 0 {
65 true
66 } else {
67 let previous_cidr = self.0.get(index - 1).unwrap();
68
69 !previous_cidr.contains(&cidr.first_address())
70 };
71
72 if pushable {
73 loop {
74 if index == self.0.len() {
75 break;
76 }
77
78 let next = self.0.get(index).unwrap();
79
80 if cidr.contains(&next.first_address()) {
81 self.0.remove(index);
82 } else {
83 break;
84 }
85 }
86
87 let mut merging = true;
88
89 while merging {
90 merging = false;
91
92 if index < self.0.len() {
93 let next_cidr = self.0.get(index).unwrap();
94
95 let next_bits = next_cidr.network_length();
96 let bits = cidr.network_length();
97
98 if bits == next_bits {
99 let next_prefix: u32 = next_cidr.first_address().into();
100 let prefix: u32 = cidr.first_address().into();
101
102 let d = next_prefix ^ prefix;
103
104 if d == 1 << (32 - bits) as u32 {
105 cidr = Ipv4Cidr::new(prefix.into(), bits - 1).unwrap();
106
107 self.0.remove(index);
108
109 merging = true;
110 }
111 }
112 }
113
114 if index > 0 {
115 let index_dec = index - 1;
116
117 let previous_cidr = self.0.get_mut(index_dec).unwrap();
118
119 let previous_bits = previous_cidr.network_length();
120 let bits = cidr.network_length();
121
122 if bits == previous_bits {
123 let previous_prefix: u32 = previous_cidr.first_address().into();
124 let prefix: u32 = cidr.first_address().into();
125
126 let d = prefix ^ previous_prefix;
127
128 if d == 1 << (32 - bits) as u32 {
129 self.0.remove(index_dec);
130
131 index = index_dec;
132
133 cidr = Ipv4Cidr::new(previous_prefix.into(), previous_bits - 1)
134 .unwrap();
135
136 merging = true;
137 }
138 }
139 }
140 }
141
142 self.0.insert(index, cidr);
143 }
144 }
145 }
146 }
147
148 #[inline]
150 pub fn contains(&self, ipv4: &Ipv4Addr) -> bool {
151 for cidr in self.0.iter() {
152 if cidr.contains(ipv4) {
153 return true;
154 }
155 }
156
157 false
158 }
159
160 #[inline]
162 pub fn size(&self) -> u64 {
163 let mut sum = 0;
164
165 for cidr in self.0.iter() {
166 sum += cidr.size();
167 }
168
169 sum
170 }
171}