Skip to content

Commit f926c45

Browse files
committed
ipv6: rewrite core ipv6 methods to operate on u128s
1 parent d289084 commit f926c45

File tree

2 files changed

+76
-69
lines changed

2 files changed

+76
-69
lines changed

src/ipv4.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl Ipv4Network {
147147
other.contains(self.ip())
148148
|| other.contains(self.broadcast())
149149
|| self.contains(other.ip())
150-
|| (self.contains(other.broadcast()))
150+
|| self.contains(other.broadcast())
151151
}
152152

153153
/// Returns the mask for this `Ipv4Network`.

src/ipv6.rs

Lines changed: 75 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::error::IpNetworkError;
22
use crate::parse::{cidr_parts, parse_prefix};
3-
use std::{cmp, convert::TryFrom, fmt, net::Ipv6Addr, str::FromStr};
3+
use std::{convert::TryFrom, fmt, net::Ipv6Addr, str::FromStr};
44

55
const IPV6_BITS: u8 = 128;
66
const IPV6_SEGMENT_BITS: u8 = 16;
@@ -87,6 +87,23 @@ impl Ipv6Network {
8787

8888
/// Constructs without checking prefix a new `Ipv6Network` from any `Ipv6Addr,
8989
/// and a prefix denoting the network size.
90+
///
91+
/// # Safety
92+
///
93+
/// The caller must ensure that the prefix is less than or equal to 32.
94+
///
95+
/// # Examples
96+
///
97+
/// ```
98+
/// use std::net::Ipv6Addr;
99+
/// use ipnetwork::Ipv6Network;
100+
///
101+
/// let prefix = 64;
102+
/// let addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
103+
///
104+
/// debug_assert!(prefix <= 128);
105+
/// let net = unsafe { Ipv6Network::new_unchecked(addr, prefix) };
106+
/// ```
90107
pub const unsafe fn new_unchecked(addr: Ipv6Addr, prefix: u8) -> Ipv6Network {
91108
Ipv6Network { addr, prefix }
92109
}
@@ -106,6 +123,10 @@ impl Ipv6Network {
106123
/// Returns an iterator over `Ipv6Network`. Each call to `next` will return the next
107124
/// `Ipv6Addr` in the given network. `None` will be returned when there are no more
108125
/// addresses.
126+
///
127+
/// # Warning
128+
///
129+
/// This can return up to 2^128 addresses, which will take a _long_ time to iterate over.
109130
pub fn iter(&self) -> Ipv6NetworkIterator {
110131
let dec = u128::from(self.addr);
111132
let max = u128::max_value();
@@ -123,42 +144,6 @@ impl Ipv6Network {
123144
}
124145
}
125146

126-
/// Returns the address of the network denoted by this `Ipv6Network`.
127-
/// This means the lowest possible IPv6 address inside of the network.
128-
///
129-
/// # Examples
130-
///
131-
/// ```
132-
/// use std::net::Ipv6Addr;
133-
/// use ipnetwork::Ipv6Network;
134-
///
135-
/// let net: Ipv6Network = "2001:db8::/96".parse().unwrap();
136-
/// assert_eq!(net.network(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
137-
/// ```
138-
pub fn network(&self) -> Ipv6Addr {
139-
let mask = u128::from(self.mask());
140-
let ip = u128::from(self.addr) & mask;
141-
Ipv6Addr::from(ip)
142-
}
143-
144-
/// Returns the broadcast address of this `Ipv6Network`.
145-
/// This means the highest possible IPv4 address inside of the network.
146-
///
147-
/// # Examples
148-
///
149-
/// ```
150-
/// use std::net::Ipv6Addr;
151-
/// use ipnetwork::Ipv6Network;
152-
///
153-
/// let net: Ipv6Network = "2001:db8::/96".parse().unwrap();
154-
/// assert_eq!(net.broadcast(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xffff, 0xffff));
155-
/// ```
156-
pub fn broadcast(&self) -> Ipv6Addr {
157-
let mask = u128::from(self.mask());
158-
let broadcast = u128::from(self.addr) | !mask;
159-
Ipv6Addr::from(broadcast)
160-
}
161-
162147
pub fn ip(&self) -> Ipv6Addr {
163148
self.addr
164149
}
@@ -180,8 +165,9 @@ impl Ipv6Network {
180165
/// Checks if the given `Ipv6Network` is partly contained in other.
181166
pub fn overlaps(self, other: Ipv6Network) -> bool {
182167
other.contains(self.ip())
183-
|| (other.contains(self.broadcast())
184-
|| (self.contains(other.ip()) || (self.contains(other.broadcast()))))
168+
|| other.contains(self.broadcast())
169+
|| self.contains(other.ip())
170+
|| self.contains(other.broadcast())
185171
}
186172

187173
/// Returns the mask for this `Ipv6Network`.
@@ -199,17 +185,47 @@ impl Ipv6Network {
199185
/// assert_eq!(net.mask(), Ipv6Addr::new(0xffff, 0xffff, 0, 0, 0, 0, 0, 0));
200186
/// ```
201187
pub fn mask(&self) -> Ipv6Addr {
202-
let mut segments = [0; 16];
203-
for (i, chunk) in segments.chunks_mut(2).enumerate() {
204-
let bits_remaining = self.prefix.saturating_sub(i as u8 * 16);
205-
let set_bits = cmp::min(bits_remaining, 16);
206-
let mask = !(0xffff >> set_bits) as u16;
207-
chunk[0] = (mask >> 8) as u8;
208-
chunk[1] = mask as u8;
209-
}
210-
Ipv6Addr::from(segments)
188+
debug_assert!(self.prefix <= IPV6_BITS);
189+
190+
let mask = u128::MAX << (IPV6_BITS - self.prefix);
191+
Ipv6Addr::from(mask)
192+
}
193+
194+
/// Returns the address of the network denoted by this `Ipv6Network`.
195+
/// This means the lowest possible IPv6 address inside of the network.
196+
///
197+
/// # Examples
198+
///
199+
/// ```
200+
/// use std::net::Ipv6Addr;
201+
/// use ipnetwork::Ipv6Network;
202+
///
203+
/// let net: Ipv6Network = "2001:db8::/96".parse().unwrap();
204+
/// assert_eq!(net.network(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
205+
/// ```
206+
pub fn network(&self) -> Ipv6Addr {
207+
let mask = u128::from(self.mask());
208+
let network = u128::from(self.addr) & mask;
209+
Ipv6Addr::from(network)
210+
}
211+
212+
/// Returns the broadcast address of this `Ipv6Network`.
213+
/// This means the highest possible IPv4 address inside of the network.
214+
///
215+
/// # Examples
216+
///
217+
/// ```
218+
/// use std::net::Ipv6Addr;
219+
/// use ipnetwork::Ipv6Network;
220+
///
221+
/// let net: Ipv6Network = "2001:db8::/96".parse().unwrap();
222+
/// assert_eq!(net.broadcast(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xffff, 0xffff));
223+
/// ```
224+
pub fn broadcast(&self) -> Ipv6Addr {
225+
let mask = u128::from(self.mask());
226+
let broadcast = u128::from(self.addr) | !mask;
227+
Ipv6Addr::from(broadcast)
211228
}
212-
213229

214230
/// Checks if a given `Ipv6Addr` is in this `Ipv6Network`
215231
///
@@ -225,14 +241,10 @@ impl Ipv6Network {
225241
/// ```
226242
#[inline]
227243
pub fn contains(&self, ip: Ipv6Addr) -> bool {
228-
let a = self.addr.segments();
229-
let b = ip.segments();
230-
let addrs = Iterator::zip(a.iter(), b.iter());
231-
self.mask()
232-
.segments()
233-
.iter()
234-
.zip(addrs)
235-
.all(|(mask, (a, b))| a & mask == b & mask)
244+
let ip = u128::from(ip);
245+
let net = u128::from(self.network());
246+
let mask = u128::from(self.mask());
247+
(ip & mask) == net
236248
}
237249

238250
/// Returns number of possible host addresses in this `Ipv6Network`.
@@ -250,12 +262,12 @@ impl Ipv6Network {
250262
/// assert_eq!(tinynet.size(), 1);
251263
/// ```
252264
pub fn size(&self) -> u128 {
253-
let host_bits = u32::from(IPV6_BITS - self.prefix);
254-
2u128.pow(host_bits)
265+
debug_assert!(self.prefix <= IPV6_BITS);
266+
1 << (IPV6_BITS - self.prefix)
255267
}
256268

257269
/// Returns the `n`:th address within this network.
258-
/// The adresses are indexed from 0 and `n` must be smaller than the size of the network.
270+
/// The addresses are indexed from 0 and `n` must be smaller than the size of the network.
259271
///
260272
/// # Examples
261273
///
@@ -296,14 +308,12 @@ impl FromStr for Ipv6Network {
296308
type Err = IpNetworkError;
297309
fn from_str(s: &str) -> Result<Self, Self::Err> {
298310
let (addr_str, prefix_str) = cidr_parts(s)?;
299-
let addr = Ipv6Addr::from_str(addr_str).map_err(|e| IpNetworkError::InvalidAddr(e.to_string()))?;
311+
let addr = Ipv6Addr::from_str(addr_str)?;
300312
let prefix = parse_prefix(prefix_str.unwrap_or(&IPV6_BITS.to_string()), IPV6_BITS)?;
301313
Ipv6Network::new(addr, prefix)
302314
}
303315
}
304316

305-
306-
307317
impl TryFrom<&str> for Ipv6Network {
308318
type Error = IpNetworkError;
309319

@@ -694,7 +704,7 @@ mod test {
694704
let other: Ipv6Network = "2001:DB8:ACAD::1/64".parse().unwrap();
695705
let other2: Ipv6Network = "2001:DB8:ACAD::20:2/64".parse().unwrap();
696706

697-
assert_eq!(other2.overlaps(other), true);
707+
assert!(other2.overlaps(other));
698708
}
699709

700710
#[test]
@@ -726,9 +736,6 @@ mod test {
726736
net.nth(65538).unwrap(),
727737
Ipv6Addr::from_str("ff01::1:2").unwrap()
728738
);
729-
assert_eq!(
730-
net.nth(net.size()),
731-
None
732-
);
739+
assert_eq!(net.nth(net.size()), None);
733740
}
734741
}

0 commit comments

Comments
 (0)