dia_ip_range/ip_v4_range/ip_v4_range_iter.rs
1/*
2==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--
3
4Dia-IP-Range
5
6Copyright (C) 2021-2024 Anonymous
7
8There are several releases over multiple years,
9they are listed as ranges, such as: "2021-2024".
10
11This program is free software: you can redistribute it and/or modify
12it under the terms of the GNU Lesser General Public License as published by
13the Free Software Foundation, either version 3 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19GNU Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public License
22along with this program. If not, see <https://www.gnu.org/licenses/>.
23
24::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
25*/
26
27//! # IPv4 range iter
28
29#![cfg(feature="iter")]
30#![doc(cfg(feature="iter"))]
31
32use {
33 std::net::IpAddr,
34 crate::IPv4ComponentRange,
35 super::IPv4Range,
36 perm::{Buffer, PermIter},
37};
38
39#[cfg(test)]
40use {
41 alloc::{
42 collections::BTreeSet,
43 string::ToString,
44 },
45};
46
47/// # IPv4 range iter
48///
49/// **WARNING:** The order of generated items is **not** guaranteed to be constant between crate versions.
50///
51/// ## Examples
52///
53/// ```
54/// use {
55/// core::str::FromStr,
56/// std::{
57/// collections::BTreeSet,
58/// net::IpAddr,
59/// },
60///
61/// dia_ip_range::{IPv4Range, IPv4RangeIter},
62/// };
63///
64/// let buffer = IPv4RangeIter::new_buffer();
65/// let iter = IPv4RangeIter::new(
66/// IPv4Range::from_str("10.0.0.[2,9]")?,
67/// &buffer,
68/// );
69/// assert_eq!(
70/// iter.collect::<BTreeSet<_>>(),
71/// [
72/// [10, 0, 0, 2], [10, 0, 0, 3], [10, 0, 0, 4], [10, 0, 0, 5],
73/// [10, 0, 0, 6], [10, 0, 0, 7], [10, 0, 0, 8], [10, 0, 0, 9],
74/// ].into_iter().map(|i| IpAddr::from(i)).collect(),
75/// );
76///
77/// # dia_ip_range::Result::Ok(())
78/// ```
79#[derive(Debug, Eq, PartialEq, Hash)]
80pub struct IPv4RangeIter<'a> {
81 iter: PermIter<'a, IPv4ComponentRange>,
82}
83
84impl<'a> IPv4RangeIter<'a> {
85
86 /// # Makes new buffer for use with `new()`
87 ///
88 /// This is a shortcut, so you don't have to manually declare [`perm`][crate:perm] crate in your `Cargo.toml` file.
89 ///
90 /// [crate:perm]: https://bitbucket.org/haibison/perm
91 pub fn new_buffer() -> Buffer<u8> {
92 Buffer::with_capacity(4)
93 }
94
95 /// # Makes new instance
96 ///
97 /// Output buffer is used for better performance.
98 ///
99 /// ## Panics
100 ///
101 /// Each buffer can only be used by one instance of `IPv4RangeIter`. Sharing it to multiple instances will cause panics.
102 pub fn new<I>(ip_v4_range: I, buffer: &'a Buffer<u8>) -> Self where I: Into<IPv4Range> {
103 let ip_v4_range = ip_v4_range.into();
104 Self {
105 iter: PermIter::new(
106 alloc::vec![ip_v4_range.a, ip_v4_range.b, ip_v4_range.c, ip_v4_range.d],
107 buffer,
108 ),
109 }
110 }
111
112}
113
114impl Iterator for IPv4RangeIter<'_> {
115
116 type Item = IpAddr;
117
118 fn next(&mut self) -> Option<Self::Item> {
119 self.nth(0)
120 }
121
122 fn nth(&mut self, n: usize) -> Option<Self::Item> {
123 self.iter.nth(n).map(|d| IpAddr::from([d[0], d[1], d[2], d[3]]))
124 }
125
126}
127
128#[test]
129fn test_ip_v4_range_iters() -> crate::Result<()> {
130 use {
131 alloc::borrow::Cow,
132 core::str::FromStr,
133 };
134
135 let buffer = IPv4RangeIter::new_buffer();
136
137 {
138 let iter = IPv4RangeIter::new(IPv4Range::from((192, 168, 0..=2, 0..=2)), &buffer);
139 assert_eq!(
140 [
141 "192.168.0.0", "192.168.1.0", "192.168.2.0",
142 "192.168.0.1", "192.168.1.1", "192.168.2.1",
143 "192.168.0.2", "192.168.1.2", "192.168.2.2",
144 ].into_iter().map(|s| Cow::Borrowed(s)).collect::<BTreeSet<_>>(),
145 iter.map(|i| i.to_string().into()).collect(),
146 );
147 }
148
149 {
150 let mut iter = IPv4RangeIter::new(IPv4Range::from((0, 0, 0, 0)), &buffer);
151 assert_eq!(iter.next().unwrap().to_string(), "0.0.0.0");
152 assert!(iter.next().is_none());
153 }
154
155 for ip in ["0.0.0.[1,0]", "0.0.0.(0,0)", "0.0.0.(0,1)"] {
156 assert_eq!(IPv4RangeIter::new(IPv4Range::from_str(ip)?, &buffer).count(), 0);
157 }
158 for ip in ["0.1.0.1", "0.0.0.[0,0]", "0.0.0.[0,1)", "0.(0,1].0.0", "0.0.0.(1,3)"] {
159 assert_eq!(IPv4RangeIter::new(IPv4Range::from_str(ip)?, &buffer).count(), 1);
160 }
161
162 Ok(())
163}