1#[cfg(feature = "bitstring")]
2use bitstring::FixedBitString;
3
4use core::{
5 fmt,
6 net::{
7 Ipv4Addr,
8 Ipv6Addr,
9 },
10 str::FromStr,
11};
12
13use crate::{
14 errors::*,
15 internal_traits::{
16 PrivCidr,
17 PrivUnspecAddress,
18 },
19 Cidr,
20 Family,
21 InetIterator,
22 Ipv4Cidr,
23 Ipv4Inet,
24 Ipv4InetPair,
25 Ipv6Cidr,
26 Ipv6Inet,
27 Ipv6InetPair,
28};
29
30macro_rules! impl_cidr_for {
31 ($n:ident : inet $inet:ident : addr $addr:ident : pair $pair:ident : family $family:expr) => {
32 #[cfg(feature = "bitstring")]
33 impl bitstring::BitString for $n {
34 fn get(&self, ndx: usize) -> bool {
35 self.address.get(ndx)
36 }
37
38 fn set(&mut self, ndx: usize, bit: bool) {
39 assert!(ndx < self.network_length as usize);
40 self.address.set(ndx, bit);
41 }
42
43 fn flip(&mut self, ndx: usize) {
44 assert!(ndx < self.network_length as usize);
45 self.address.flip(ndx);
46 }
47
48 fn len(&self) -> usize {
49 self.network_length as usize
50 }
51
52 fn clip(&mut self, len: usize) {
53 if len > 255 {
54 return;
55 }
56 self.address.set_false_from(len);
57 self.network_length = core::cmp::min(self.network_length, len as u8);
58 }
59
60 fn append(&mut self, bit: bool) {
61 self.address.set(self.network_length as usize, bit);
62 self.network_length += 1;
63 }
64
65 fn null() -> Self {
66 Self {
67 address: FixedBitString::new_all_false(),
68 network_length: 0,
69 }
70 }
71
72 fn shared_prefix_len(&self, other: &Self) -> usize {
73 let max_len = core::cmp::min(self.network_length, other.network_length) as usize;
74 core::cmp::min(
75 FixedBitString::shared_prefix_len(&self.address, &other.address),
76 max_len,
77 )
78 }
79 }
80
81 impl $n {
82 pub const fn new(addr: $addr, len: u8) -> Result<Self, NetworkParseError> {
87 if len > $family.len() {
88 Err(NetworkParseError::NetworkLengthTooLongError(
89 NetworkLengthTooLongError::new(len as usize, $family),
90 ))
91 } else if !<$addr as PrivUnspecAddress>::_Tools::_has_zero_host_part(addr, len) {
92 Err(NetworkParseError::InvalidHostPart)
93 } else {
94 Ok(Self {
95 address: addr,
96 network_length: len,
97 })
98 }
99 }
100
101 pub const fn new_host(addr: $addr) -> Self {
104 Self {
105 address: addr,
106 network_length: $family.len(),
107 }
108 }
109
110 pub const fn iter(&self) -> InetIterator<$addr> {
114 self._range_pair().iter()
115 }
116
117 pub const fn first_address(&self) -> $addr {
119 self.address
120 }
121
122 pub const fn first(&self) -> $inet {
124 $inet {
125 address: self.first_address(),
126 network_length: self.network_length,
127 }
128 }
129
130 pub const fn last_address(&self) -> $addr {
132 <$addr as PrivUnspecAddress>::_Tools::_last_address(
133 self.address,
134 self.network_length,
135 )
136 }
137
138 pub const fn last(&self) -> $inet {
140 $inet {
141 address: self.last_address(),
142 network_length: self.network_length,
143 }
144 }
145
146 pub const fn network_length(&self) -> u8 {
148 self.network_length
149 }
150
151 pub const fn family(&self) -> Family {
156 $family
157 }
158
159 pub const fn is_host_address(&self) -> bool {
161 self.network_length() == self.family().len()
162 }
163
164 pub const fn mask(&self) -> $addr {
167 <$addr as PrivUnspecAddress>::_Tools::_network_mask(self.network_length)
168 }
169
170 pub const fn contains(&self, addr: &$addr) -> bool {
172 <$addr as PrivUnspecAddress>::_Tools::_prefix_match(
173 self.address,
174 *addr,
175 self.network_length,
176 )
177 }
178
179 pub(crate) const fn _range_pair(&self) -> $pair {
180 $pair {
181 first: self.first_address(),
182 second: self.last_address(),
183 network_length: self.network_length,
184 }
185 }
186 }
187
188 impl PrivCidr for $n {}
189
190 impl Cidr for $n {
191 type Address = $addr;
192
193 fn new(addr: $addr, len: u8) -> Result<Self, NetworkParseError> {
194 Self::new(addr, len)
195 }
196
197 fn new_host(addr: $addr) -> Self {
198 Self::new_host(addr)
199 }
200
201 fn iter(&self) -> InetIterator<$addr> {
202 self.iter()
203 }
204
205 fn first_address(&self) -> $addr {
206 self.first_address()
207 }
208
209 fn first(&self) -> $inet {
210 self.first()
211 }
212
213 fn last_address(&self) -> $addr {
214 self.last_address()
215 }
216
217 fn last(&self) -> $inet {
218 self.last()
219 }
220
221 fn network_length(&self) -> u8 {
222 self.network_length()
223 }
224
225 fn family(&self) -> Family {
226 self.family()
227 }
228
229 fn is_host_address(&self) -> bool {
230 self.is_host_address()
231 }
232
233 fn mask(&self) -> $addr {
234 self.mask()
235 }
236
237 fn contains(&self, addr: &$addr) -> bool {
238 self.contains(addr)
239 }
240 }
241
242 impl fmt::Debug for $n {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 write!(f, "{:?}/{}", self.address, self.network_length)
245 }
246 }
247
248 impl fmt::Display for $n {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 if f.alternate() || !self.is_host_address() {
251 write!(f, "{}/{}", self.address, self.network_length)?;
252 } else {
253 write!(f, "{}", self.address)?;
254 }
255 Ok(())
256 }
257 }
258
259 impl PartialOrd<$n> for $n {
260 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
261 Some(self.cmp(other))
262 }
263 }
264
265 impl Ord for $n {
266 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
267 self.address
268 .cmp(&other.address)
269 .then(self.network_length.cmp(&other.network_length))
270 }
271 }
272
273 impl FromStr for $n {
274 type Err = NetworkParseError;
275
276 fn from_str(s: &str) -> Result<$n, NetworkParseError> {
277 crate::parsers::parse_cidr(s, FromStr::from_str)
278 }
279 }
280
281 impl From<$addr> for $n {
282 fn from(address: $addr) -> Self {
283 Self::new_host(address)
284 }
285 }
286
287 impl IntoIterator for $n {
289 type IntoIter = $crate::InetIterator<$addr>;
290 type Item = $inet;
291
292 fn into_iter(self) -> Self::IntoIter {
293 self._range_pair().iter()
294 }
295 }
296 };
297}
298
299impl_cidr_for! {Ipv4Cidr : inet Ipv4Inet : addr Ipv4Addr : pair Ipv4InetPair : family Family::Ipv4}
300impl_cidr_for! {Ipv6Cidr : inet Ipv6Inet : addr Ipv6Addr : pair Ipv6InetPair : family Family::Ipv6}
301
302#[cfg(test)]
303mod tests {
304 use core::net::Ipv4Addr;
305
306 use crate::Ipv4Cidr;
307
308 fn check_list_iter<T: PartialEq + core::fmt::Debug>(
309 data: impl AsRef<[T]>,
310 iter: impl IntoIterator<Item = T>,
311 ) {
312 let mut iter = iter.into_iter();
313 for elem in data.as_ref() {
314 assert_eq!(Some(elem), iter.next().as_ref());
315 }
316 assert_eq!(None, iter.next());
317 }
318
319 #[test]
320 fn v4_ref_into_iter() {
321 let cidr = Ipv4Cidr::new(Ipv4Addr::new(1, 2, 3, 0), 30).unwrap();
322 check_list_iter(
323 [
324 Ipv4Addr::new(1, 2, 3, 0),
325 Ipv4Addr::new(1, 2, 3, 1),
326 Ipv4Addr::new(1, 2, 3, 2),
327 Ipv4Addr::new(1, 2, 3, 3),
328 ],
329 cidr.into_iter().addresses(),
330 );
331 }
332
333 #[test]
334 fn v4_owned_into_iter() {
335 let cidr = Ipv4Cidr::new(Ipv4Addr::new(1, 2, 3, 0), 30).unwrap();
336 check_list_iter(
337 [
338 Ipv4Addr::new(1, 2, 3, 0),
339 Ipv4Addr::new(1, 2, 3, 1),
340 Ipv4Addr::new(1, 2, 3, 2),
341 Ipv4Addr::new(1, 2, 3, 3),
342 ],
343 cidr.into_iter().addresses(),
344 );
345 }
346}