Skip to content

Commit 30ab1fc

Browse files
authored
Merge pull request #75 from rye/iteration
Add Iterator traits
2 parents efc8b6b + 111b9e5 commit 30ab1fc

File tree

12 files changed

+978
-18
lines changed

12 files changed

+978
-18
lines changed

CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
## Unreleased
1111

12+
### Added
13+
14+
- New `SubnetIterator` iterator type for iterating over a network's subnets.
15+
- New `Netv6Addr#len() -> Option<u128>` method for computing the number of addresses contained in a network.
16+
- New `Netv6Addr#is_empty() -> bool` method for determining whether or not the network is empty.
17+
- New `Netv4Addr#len() -> Option<u32>` method for computing the number of addresses contained in a network.
18+
- New `Netv4Addr#is_empty() -> bool` method for determining whether or not the network is empty.
19+
- New `AddressIterator` iterator type for iterating over a network's addresses.
20+
1221
## [0.10.0] - 2021-07-06
22+
1323
### Changed
24+
1425
- **Breaking**: `Netv4Addr::addr`, `Netv4Addr::mask`, `Netv6Addr::addr`, and `Netv6Addr::mask` all now return `Ipv4Addr` or `Ipv6Addr` respectively instead of `&Ipv4Addr` or `&Ipv6Addr`.
1526

1627
- **Breaking**: Replaced the `derive`'d `Ord` impl with our own explicit implementation.
@@ -24,81 +35,114 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2435
- Adjusted CI configuration
2536

2637
## [0.9.0] - 2020-02-26
38+
2739
### Changed
40+
2841
- **Breaking**: Adjusted the signature of the `Contains` trait to take a type parameter.
2942

3043
Most users should not be affected in any way by this change, as the `.contains()` method still has the same syntax.
3144
However, the types for which containment can be checked are now explicitly enumerated.
3245

3346
## [0.8.0] - 2020-02-26
47+
3448
### Added
49+
3550
- `is_cidr` method on `NetAddr`, `Netv4Addr`, and `Netv6Addr` to return whether the represented netaddr is CIDR or not.
3651

3752
### Changed
53+
3854
- Updated the `serde::de` behavior to be slightly more informative and standard.
3955

4056
## [0.7.1] - 2019-01-12
57+
4158
### Added
59+
4260
- Documented a few undocumented types.
4361

4462
## [0.7.0] - 2019-12-24
63+
4564
### Added
65+
4666
- A new `Result<T, Error>` type, which is a sugar around the nascent `Error` type.
4767

4868
### Changed
69+
4970
- Renamed the `NetAddrError` type to just `Error`.
5071

5172
## [0.6.1] - 2019-11-18
73+
5274
### Added
75+
5376
- Added the `serde` feature to the `docs.rs` metadata key
5477

5578
## [0.6.0] - 2019-11-18
79+
5680
### Added
81+
5782
- Implementations for `serde::Serialize` and `serde::Deserialize` on core types, gated behind the `serde` feature
5883

5984
## [0.5.0] - 2019-10-20
85+
6086
### Added
87+
6188
- Implementation for `core::fmt::Display` on the `NetAddr` enum and the `Netv4Addr` and `Netv6Addr` structs.
6289

6390
## [0.4.1] - 2019-09-29
91+
6492
### Added
93+
6594
- Tests for the `Merge` trait.
6695
- Tests for the methods on the `Netv4Addr` and `Netv6Addr` structs.
6796
- Documentation for some items.
6897

6998
## [0.4.0] - 2019-08-25
99+
70100
### Changed
101+
71102
- Made the `mask` and `addr` methods `const` and `pub` under the `Netv4Addr` and `Netv6Addr` types.
72103

73104
## [0.3.0] - 2019-08-22
105+
74106
### Added
107+
75108
- A lot of tests to the source code in a structured way.
76109

77110
### Changed
111+
78112
- **Breaking**: Restructured the API to use lots of modules.
79113
- **Breaking**: Use the recently-stabilized `Self` type alias in the code. (requires Rust 1.37)
80114
- Began using GitHub Actions for CI instead of CircleCI.
81115

82116
### Removed
117+
83118
- The `script/clippy` script.
84119

85120
## [0.2.0] - 2019-08-12
121+
86122
### Added
123+
87124
- A Travis CI configuration for testing.
88125

89126
### Changed
127+
90128
- Existing API to use traits.
91129

92130
## [0.1.2] - 2019-07-23
131+
93132
### Fixed
133+
94134
- SPDX identifier for `Apache-2.0` in the manifest, allowing releases to be published.
95135

96136
## [0.1.1] - 2019-07-23
137+
97138
### Added
139+
98140
- A `CHANGELOG.md` file.
99141

100142
## [0.1.0] - 2019-07-23
143+
101144
### Added
145+
102146
- `NetAddr` enum with two variants (`V4`, `V6`), each containing the respective `Ipv\dAddr` class.
103147
- `#[derive]`-ed impls for `Copy`, `Clone`, `Debug`, `PartialEq`, `Eq`, `Ord`, and `Hash` on `NetAddr`.
104148
- `NetAddr#netmask` method to return the netmask address in `IpAddr` form.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ categories = ["data-structures", "network-programming"]
1515
keywords = ["netaddr", "network", "address", "cidr"]
1616

1717
[package.metadata.docs.rs]
18-
features = ["serde"]
18+
features = ["serde", "unstable"]
1919
all-features = true
2020

21+
[badges]
22+
maintenance = { status = "actively-developed" }
23+
2124
[features]
2225
default = []
26+
unstable = []
2327

2428
[dependencies]
2529
serde = { version = "~1", optional = true }

src/iter.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//! Traits for iteration over `NetAddr` types.
2+
3+
mod address;
4+
mod offset;
5+
#[cfg(feature = "unstable")]
6+
mod sibling;
7+
#[cfg(feature = "unstable")]
8+
mod subnet;
9+
10+
pub use address::*;
11+
#[cfg(feature = "unstable")]
12+
pub use sibling::*;
13+
#[cfg(feature = "unstable")]
14+
pub use subnet::*;

src/iter/address.rs

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
use crate::Contains;
2+
3+
use super::offset::Offset;
4+
5+
/// An iterator over a network's _contained addresses_.
6+
pub struct AddressIterator<Network, Address>
7+
where
8+
Network: Contains<Address> + From<Address>,
9+
{
10+
net: Network,
11+
cur: Option<Address>,
12+
}
13+
14+
impl<Network, Address> AddressIterator<Network, Address>
15+
where
16+
Network: Contains<Address> + From<Address>,
17+
{
18+
pub(crate) fn new(net: Network, cur: Option<Address>) -> Self {
19+
Self { net, cur }
20+
}
21+
}
22+
23+
/// Implementation of the [`Iterator`] trait for [`AddressIterator`].
24+
impl<Network, Address> Iterator for AddressIterator<Network, Address>
25+
where
26+
Address: Copy + Offset<u32>,
27+
Network: Contains<Address> + From<Address>,
28+
{
29+
type Item = Address;
30+
31+
/// Produce the next item.
32+
///
33+
/// The current address is offset by `1_u32` using the [`Offset`] trait, which
34+
/// may produce `None`.
35+
fn next(&mut self) -> Option<Self::Item> {
36+
let cur: Option<Self::Item> = self.cur;
37+
let next: Option<Self::Item> = cur.and_then(|cur| cur.offset(1_u32));
38+
39+
match (cur, next) {
40+
(Some(cur), Some(next)) => {
41+
if self.net.contains(&cur) {
42+
self.cur = Some(next);
43+
Some(cur)
44+
} else {
45+
None
46+
}
47+
}
48+
(Some(cur), None) => {
49+
self.cur = None;
50+
Some(cur)
51+
}
52+
(None, _) => None,
53+
}
54+
}
55+
}
56+
57+
#[cfg(test)]
58+
mod tests {
59+
use super::AddressIterator;
60+
61+
mod netv4addr {
62+
use super::*;
63+
64+
use crate::Netv4Addr;
65+
use std::net::Ipv4Addr;
66+
67+
impl crate::Netv4Addr {
68+
pub fn iter(&self) -> AddressIterator<Netv4Addr, Ipv4Addr> {
69+
AddressIterator {
70+
net: *self,
71+
cur: Some(self.addr()),
72+
}
73+
}
74+
}
75+
76+
#[test]
77+
fn loopback_slash_32_produces_one_off() {
78+
let net: Netv4Addr = "127.0.16.0/32".parse().unwrap();
79+
80+
let mut it: AddressIterator<Netv4Addr, Ipv4Addr> = net.iter();
81+
assert_eq!(it.next(), "127.0.16.0".parse::<Ipv4Addr>().ok());
82+
assert_eq!(it.next(), None);
83+
}
84+
85+
#[test]
86+
fn loopback_slash_29_produces_one_off() {
87+
let net: Netv4Addr = "127.0.16.0/29".parse().unwrap();
88+
89+
let mut it: AddressIterator<Netv4Addr, Ipv4Addr> = net.iter();
90+
assert_eq!(it.next(), "127.0.16.0".parse::<Ipv4Addr>().ok());
91+
assert_eq!(it.next(), "127.0.16.1".parse::<Ipv4Addr>().ok());
92+
assert_eq!(it.next(), "127.0.16.2".parse::<Ipv4Addr>().ok());
93+
assert_eq!(it.next(), "127.0.16.3".parse::<Ipv4Addr>().ok());
94+
assert_eq!(it.next(), "127.0.16.4".parse::<Ipv4Addr>().ok());
95+
assert_eq!(it.next(), "127.0.16.5".parse::<Ipv4Addr>().ok());
96+
assert_eq!(it.next(), "127.0.16.6".parse::<Ipv4Addr>().ok());
97+
assert_eq!(it.next(), "127.0.16.7".parse::<Ipv4Addr>().ok());
98+
assert_eq!(it.next(), None);
99+
}
100+
101+
#[test]
102+
fn loopback_max_value_properly_stops() {
103+
let net: Netv4Addr = "255.255.255.255/31".parse().unwrap();
104+
105+
let mut it: AddressIterator<Netv4Addr, Ipv4Addr> = net.iter();
106+
assert_eq!(it.next(), "255.255.255.254".parse::<Ipv4Addr>().ok());
107+
assert_eq!(it.next(), "255.255.255.255".parse::<Ipv4Addr>().ok());
108+
assert_eq!(it.next(), None);
109+
}
110+
}
111+
112+
mod netaddr {
113+
use super::*;
114+
115+
use crate::NetAddr;
116+
use std::net::IpAddr;
117+
118+
mod v4 {
119+
use super::*;
120+
121+
#[test]
122+
fn loopback_slash_32_produces_one_off() {
123+
let net: NetAddr = "127.0.16.0/32".parse().unwrap();
124+
125+
let mut it: AddressIterator<NetAddr, IpAddr> = net.iter();
126+
assert_eq!(it.next(), "127.0.16.0".parse::<IpAddr>().ok());
127+
assert_eq!(it.next(), None);
128+
}
129+
130+
#[test]
131+
fn loopback_slash_29_produces_all_ips_in_network() {
132+
let net: NetAddr = "127.0.16.0/29".parse().unwrap();
133+
134+
let mut it: AddressIterator<NetAddr, IpAddr> = net.iter();
135+
assert_eq!(it.next(), "127.0.16.0".parse::<IpAddr>().ok());
136+
assert_eq!(it.next(), "127.0.16.1".parse::<IpAddr>().ok());
137+
assert_eq!(it.next(), "127.0.16.2".parse::<IpAddr>().ok());
138+
assert_eq!(it.next(), "127.0.16.3".parse::<IpAddr>().ok());
139+
assert_eq!(it.next(), "127.0.16.4".parse::<IpAddr>().ok());
140+
assert_eq!(it.next(), "127.0.16.5".parse::<IpAddr>().ok());
141+
assert_eq!(it.next(), "127.0.16.6".parse::<IpAddr>().ok());
142+
assert_eq!(it.next(), "127.0.16.7".parse::<IpAddr>().ok());
143+
assert_eq!(it.next(), None);
144+
}
145+
146+
#[test]
147+
fn loopback_max_value_properly_stops() {
148+
let net: NetAddr = "255.255.255.255/31".parse().unwrap();
149+
150+
let mut it: AddressIterator<NetAddr, IpAddr> = net.iter();
151+
assert_eq!(it.next(), "255.255.255.254".parse::<IpAddr>().ok());
152+
assert_eq!(it.next(), "255.255.255.255".parse::<IpAddr>().ok());
153+
assert_eq!(it.next(), None);
154+
}
155+
}
156+
157+
mod v6 {
158+
use super::*;
159+
160+
#[test]
161+
fn slash_128_produces_one_off() {
162+
let net: NetAddr = "2001:db8::1/128".parse().unwrap();
163+
164+
let mut it: AddressIterator<NetAddr, IpAddr> = net.iter();
165+
assert_eq!(it.next(), "2001:db8::1".parse::<IpAddr>().ok());
166+
assert_eq!(it.next(), None);
167+
}
168+
169+
#[test]
170+
fn slash_125_produces_all_ips_in_network() {
171+
let net: NetAddr = "2001:db8::1/125".parse().unwrap();
172+
173+
let mut it: AddressIterator<NetAddr, IpAddr> = net.iter();
174+
assert_eq!(it.next(), "2001:db8::0".parse::<IpAddr>().ok());
175+
assert_eq!(it.next(), "2001:db8::1".parse::<IpAddr>().ok());
176+
assert_eq!(it.next(), "2001:db8::2".parse::<IpAddr>().ok());
177+
assert_eq!(it.next(), "2001:db8::3".parse::<IpAddr>().ok());
178+
assert_eq!(it.next(), "2001:db8::4".parse::<IpAddr>().ok());
179+
assert_eq!(it.next(), "2001:db8::5".parse::<IpAddr>().ok());
180+
assert_eq!(it.next(), "2001:db8::6".parse::<IpAddr>().ok());
181+
assert_eq!(it.next(), "2001:db8::7".parse::<IpAddr>().ok());
182+
assert_eq!(it.next(), None);
183+
}
184+
185+
#[test]
186+
fn loopback_max_value_properly_stops() {
187+
let net: NetAddr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/127"
188+
.parse()
189+
.unwrap();
190+
191+
let mut it: AddressIterator<NetAddr, IpAddr> = net.iter();
192+
assert_eq!(
193+
it.next(),
194+
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"
195+
.parse::<IpAddr>()
196+
.ok()
197+
);
198+
assert_eq!(
199+
it.next(),
200+
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
201+
.parse::<IpAddr>()
202+
.ok()
203+
);
204+
assert_eq!(it.next(), None);
205+
}
206+
}
207+
}
208+
}

0 commit comments

Comments
 (0)