ip_network/
iterator.rs

1use std::net::{Ipv4Addr, Ipv6Addr};
2use crate::{Ipv4Network, Ipv6Network};
3use crate::helpers;
4
5#[cfg(target_pointer_width = "16")]
6const POINTER_WIDTH: u32 = 16;
7#[cfg(target_pointer_width = "32")]
8const POINTER_WIDTH: u32 = 32;
9#[cfg(target_pointer_width = "64")]
10const POINTER_WIDTH: u32 = 64;
11#[cfg(target_pointer_width = "128")]
12const POINTER_WIDTH: u32 = 128;
13
14/// IPv4 range iterator.
15pub struct Ipv4RangeIterator {
16    current: u32,
17    to: u32,
18    is_done: bool,
19}
20
21impl Ipv4RangeIterator {
22    /// Constructs new `Ipv4RangeIterator` for given range, both `from` and `to` address are inclusive.
23    ///
24    /// # Panics
25    ///
26    /// When `to` address is bigger or same than `from` address.
27    ///
28    /// # Examples
29    ///
30    /// ```
31    /// use std::net::Ipv4Addr;
32    /// use ip_network::iterator::Ipv4RangeIterator;
33    ///
34    /// let mut iterator = Ipv4RangeIterator::new(
35    ///     Ipv4Addr::new(192, 168, 2, 0),
36    ///     Ipv4Addr::new(192, 168, 2, 255)
37    /// );
38    /// assert_eq!(iterator.next().unwrap(), Ipv4Addr::new(192, 168, 2, 0));
39    /// assert_eq!(iterator.next().unwrap(), Ipv4Addr::new(192, 168, 2, 1));
40    /// assert_eq!(iterator.last().unwrap(), Ipv4Addr::new(192, 168, 2, 255));
41    /// ```
42    pub fn new(from: Ipv4Addr, to: Ipv4Addr) -> Self {
43        let current = u32::from(from);
44        let to = u32::from(to);
45        assert!(to >= current);
46        Self {
47            current,
48            to,
49            is_done: false,
50        }
51    }
52
53    /// Constructs new `Ipv4RangeIterator` that iterates host (without network and broadcast address)
54    /// IPs in Ipv4Network.
55    pub fn hosts(network: Ipv4Network) -> Self {
56        if network.netmask() >= 31 {
57            // Network doesn't contains any host IPs, create empty iterator.
58            Self {
59                current: 0,
60                to: 0,
61                is_done: true,
62            }
63        } else {
64            let from = Ipv4Addr::from(u32::from(network.network_address()) + 1);
65            let to = Ipv4Addr::from(u32::from(network.broadcast_address()) - 1);
66            Self::new(from, to)
67        }
68    }
69}
70
71impl Iterator for Ipv4RangeIterator {
72    type Item = Ipv4Addr;
73
74    fn next(&mut self) -> Option<Self::Item> {
75        if self.current <= self.to && !self.is_done {
76            let output = self.current;
77
78            match self.current.checked_add(1) {
79                Some(x) => self.current = x,
80                None => self.is_done = true,
81            };
82
83            Some(Self::Item::from(output))
84        } else {
85            None
86        }
87    }
88
89    fn size_hint(&self) -> (usize, Option<usize>) {
90        if self.is_done {
91            return (0, Some(0));
92        }
93
94        let remaining = (self.to - self.current + 1) as usize;
95        (remaining, Some(remaining))
96    }
97}
98
99impl ExactSizeIterator for Ipv4RangeIterator {}
100
101/// Iterates over new created IPv4 network from given network.
102pub struct Ipv4NetworkIterator {
103    current: u32,
104    to: u32,
105    new_netmask: u8,
106    is_done: bool,
107}
108
109impl Ipv4NetworkIterator {
110    /// Constructs new `Ipv4NetworkIterator`, that iterates over networks based on `network` and
111    /// `new_netmask`. If network has already netmask 32 or when is the same as `new_netmask`, empty
112    /// iterator is returned.
113    ///
114    /// # Panics
115    ///
116    /// When `new_netmask` is smaller than `network` netmask or when `net_netmask` is bigger than 32.
117    pub fn new(network: Ipv4Network, new_netmask: u8) -> Self {
118        assert!(new_netmask <= Ipv4Network::LENGTH);
119
120        if network.netmask() == Ipv4Network::LENGTH || network.netmask() == new_netmask {
121            return Self {
122                current: 0,
123                to: 0,
124                new_netmask: 0,
125                is_done: true,
126            };
127        }
128
129        assert!(network.netmask() < new_netmask);
130
131        let current = u32::from(network.network_address());
132        let mask =
133            !helpers::bite_mask(32 - (new_netmask - network.netmask())) << (32 - new_netmask);
134        let to = current | mask;
135
136        Self {
137            current,
138            to,
139            new_netmask,
140            is_done: false,
141        }
142    }
143
144    fn step(&self) -> u32 {
145        1 << (32 - self.new_netmask)
146    }
147}
148
149impl Iterator for Ipv4NetworkIterator {
150    type Item = Ipv4Network;
151
152    fn next(&mut self) -> Option<Self::Item> {
153        if self.current <= self.to && !self.is_done {
154            let output = self.current;
155
156            match self.current.checked_add(self.step()) {
157                Some(x) => self.current = x,
158                None => self.is_done = true,
159            };
160
161            Some(Self::Item {
162                network_address: Ipv4Addr::from(output),
163                netmask: self.new_netmask,
164            })
165        } else {
166            None
167        }
168    }
169
170    fn size_hint(&self) -> (usize, Option<usize>) {
171        if self.is_done {
172            return (0, Some(0));
173        }
174
175        let remaining = ((self.to - self.current) / self.step() + 1) as usize;
176        (remaining, Some(remaining))
177    }
178}
179
180impl ExactSizeIterator for Ipv4NetworkIterator {}
181
182/// Iterates over new created IPv6 network from given network.
183pub struct Ipv6NetworkIterator {
184    current: u128,
185    to: u128,
186    new_netmask: u8,
187    is_done: bool,
188}
189
190impl Ipv6NetworkIterator {
191    /// Constructs new `Ipv6NetworkIterator`, that iterates over networks based on `network` and
192    /// `new_netmask`. If network has already netmask 128 or when is the same as `new_netmask`, empty
193    /// iterator is returned.
194    ///
195    /// # Panics
196    ///
197    /// When `new_netmask` is smaller than `network` netmask or when `net_netmask` is bigger than 128.
198    pub fn new(network: Ipv6Network, new_netmask: u8) -> Self {
199        assert!(new_netmask <= Ipv6Network::LENGTH);
200
201        if network.netmask() == Ipv6Network::LENGTH || network.netmask() == new_netmask {
202            return Self {
203                current: 0,
204                to: 0,
205                new_netmask: 0,
206                is_done: true,
207            };
208        }
209
210        assert!(network.netmask() < new_netmask);
211
212        let current = u128::from(network.network_address());
213        let mask = !helpers::bite_mask_u128(128 - (new_netmask - network.netmask()))
214            << (128 - new_netmask);
215        let to = current | mask;
216
217        Self {
218            current,
219            to,
220            new_netmask,
221            is_done: false,
222        }
223    }
224
225    fn step(&self) -> u128 {
226        1 << (128 - self.new_netmask)
227    }
228
229    pub fn real_len(&self) -> u128 {
230        if self.is_done {
231            return 0;
232        }
233
234        ((self.to - self.current) / self.step()).saturating_add(1)
235    }
236}
237
238impl Iterator for Ipv6NetworkIterator {
239    type Item = Ipv6Network;
240
241    fn next(&mut self) -> Option<Self::Item> {
242        if self.current <= self.to && !self.is_done {
243            let output = self.current;
244
245            match self.current.checked_add(self.step()) {
246                Some(x) => self.current = x,
247                None => self.is_done = true,
248            };
249
250            Some(Self::Item {
251                network_address: Ipv6Addr::from(output),
252                netmask: self.new_netmask,
253            })
254        } else {
255            None
256        }
257    }
258
259    fn size_hint(&self) -> (usize, Option<usize>) {
260        let remaining = self.real_len();
261
262        if 128 - remaining.leading_zeros() > POINTER_WIDTH {
263            (usize::MAX, None)
264        } else {
265            let remaining_u64 = remaining as u64;
266            (remaining_u64 as usize, Some(remaining_u64 as usize))
267        }
268    }
269}
270
271impl ExactSizeIterator for Ipv6NetworkIterator {}
272
273#[cfg(test)]
274mod tests {
275    use std::net::{Ipv4Addr, Ipv6Addr};
276    use crate::{Ipv4Network, Ipv6Network};
277    use super::{Ipv4NetworkIterator, Ipv4RangeIterator, Ipv6NetworkIterator};
278
279    #[test]
280    fn ipv4_range_iterator() {
281        let mut iterator = Ipv4RangeIterator::new(
282            Ipv4Addr::new(192, 168, 2, 0),
283            Ipv4Addr::new(192, 168, 2, 255),
284        );
285        assert_eq!(iterator.next().unwrap(), Ipv4Addr::new(192, 168, 2, 0));
286        assert_eq!(iterator.next().unwrap(), Ipv4Addr::new(192, 168, 2, 1));
287        assert_eq!(iterator.last().unwrap(), Ipv4Addr::new(192, 168, 2, 255));
288    }
289
290    #[test]
291    fn ipv4_range_iterator_length() {
292        let mut iterator = Ipv4RangeIterator::new(
293            Ipv4Addr::new(192, 168, 2, 0),
294            Ipv4Addr::new(192, 168, 2, 255),
295        );
296        assert_eq!(iterator.len(), 256);
297        iterator.next().unwrap();
298        assert_eq!(iterator.len(), 255);
299        assert_eq!(iterator.collect::<Vec<_>>().len(), 255);
300    }
301
302    #[test]
303    fn ipv4_range_iterator_same_values() {
304        let mut iterator = Ipv4RangeIterator::new(
305            Ipv4Addr::new(255, 255, 255, 255),
306            Ipv4Addr::new(255, 255, 255, 255),
307        );
308        assert_eq!(iterator.len(), 1);
309        assert_eq!(iterator.next().unwrap(), Ipv4Addr::new(255, 255, 255, 255));
310        assert!(iterator.next().is_none());
311        assert_eq!(iterator.len(), 0);
312    }
313
314    #[test]
315    fn ipv4_network_iterator() {
316        let network = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 0), 8).unwrap();
317        let mut iterator = Ipv4NetworkIterator::new(network, 16);
318
319        assert_eq!(iterator.len(), 256);
320        assert_eq!(
321            iterator.next().unwrap(),
322            Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 0), 16).unwrap()
323        );
324        assert_eq!(
325            iterator.next().unwrap(),
326            Ipv4Network::new(Ipv4Addr::new(127, 1, 0, 0), 16).unwrap()
327        );
328        assert_eq!(
329            iterator.next().unwrap(),
330            Ipv4Network::new(Ipv4Addr::new(127, 2, 0, 0), 16).unwrap()
331        );
332        assert_eq!(
333            iterator.last().unwrap(),
334            Ipv4Network::new(Ipv4Addr::new(127, 255, 0, 0), 16).unwrap()
335        );
336    }
337
338    #[test]
339    fn ipv4_network_iterator_empty() {
340        let network = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 0), 32).unwrap();
341        let iterator = Ipv4NetworkIterator::new(network, 32);
342        assert_eq!(0, iterator.len());
343    }
344
345    #[test]
346    fn ipv6_network_iterator() {
347        let ip = Ipv6Addr::new(0x2001, 0, 0, 0, 0, 0, 0, 0);
348        let network = Ipv6Network::new(ip, 16).unwrap();
349        let mut iterator = Ipv6NetworkIterator::new(network, 17);
350
351        assert_eq!(2, iterator.len());
352        assert_eq!(iterator.next().unwrap(), Ipv6Network::new(ip, 17).unwrap());
353        assert_eq!(
354            iterator.next().unwrap(),
355            Ipv6Network::new(Ipv6Addr::new(0x2001, 0x8000, 0, 0, 0, 0, 0, 0), 17).unwrap()
356        );
357        assert!(iterator.next().is_none());
358    }
359
360    #[test]
361    #[should_panic] // because range is bigger than `usize` on 64bit machine
362    #[cfg(not(miri))] // currently, miri doesnt support should_panic tests
363    fn ipv6_network_iterator_whole_range_len() {
364        let ip = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
365        let network = Ipv6Network::new(ip, 0).unwrap();
366        let iterator = Ipv6NetworkIterator::new(network, 128);
367
368        iterator.len();
369    }
370
371    #[test]
372    fn ipv6_network_iterator_whole_range_real_len() {
373        let ip = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
374        let network = Ipv6Network::new(ip, 0).unwrap();
375        let iterator = Ipv6NetworkIterator::new(network, 128);
376
377        assert_eq!(iterator.real_len(), u128::MAX);
378    }
379
380    #[test]
381    fn ipv6_network_iterator_whole_range() {
382        let ip = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
383        let network = Ipv6Network::new(ip, 0).unwrap();
384        let mut iterator = Ipv6NetworkIterator::new(network, 128);
385
386        assert_eq!(
387            iterator.next().unwrap(),
388            Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 128).unwrap()
389        );
390        assert_eq!(
391            iterator.next().unwrap(),
392            Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 128).unwrap()
393        );
394    }
395}