Skip to content

Commit 2e17cd8

Browse files
committed
Add Ipv{4,6}AddrMask
1 parent d361a9a commit 2e17cd8

File tree

4 files changed

+200
-33
lines changed

4 files changed

+200
-33
lines changed

Diff for: library/std/src/net/ip/mask.rs

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#![allow(missing_docs)]
2+
#![unstable(feature = "ip_mask", issue = "none")]
3+
4+
use super::{Ipv4Addr, Ipv6Addr};
5+
use crate::fmt;
6+
use crate::ops;
7+
8+
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
9+
pub struct Ipv4AddrMask {
10+
mask: u32,
11+
}
12+
13+
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
14+
pub struct Ipv6AddrMask {
15+
mask: u128,
16+
}
17+
18+
impl Ipv4AddrMask {
19+
pub const fn from_address(address: Ipv4Addr) -> Ipv4AddrMask {
20+
Ipv4AddrMask { mask: u32::from_be_bytes(address.octets()) }
21+
}
22+
23+
// 8 -> `255.0.0.0`
24+
pub const fn from_prefix(len: u32) -> Ipv4AddrMask {
25+
let mask = {
26+
if len == 0 {
27+
0
28+
} else {
29+
// shift will not overflow as len > 0, so u32::BITS - len < 32
30+
u32::MAX << (u32::BITS - len)
31+
}
32+
};
33+
34+
Ipv4AddrMask { mask }
35+
}
36+
37+
// 8 -> `0.0.0.255`
38+
pub const fn from_suffix(len: u32) -> Ipv4AddrMask {
39+
Ipv4AddrMask::from_prefix(len).invert()
40+
}
41+
42+
// `1.2.3.4` + `255.255.255.0` -> `1.2.3.0`
43+
pub const fn apply(&self, address: &Ipv4Addr) -> Ipv4Addr {
44+
let masked = u32::from_be_bytes(address.octets()) & self.mask;
45+
Ipv4Addr::from_u32(masked)
46+
}
47+
48+
// `255.255.255.0` -> `0.0.0.255`
49+
pub const fn invert(self) -> Ipv4AddrMask {
50+
Ipv4AddrMask { mask: !self.mask }
51+
}
52+
}
53+
54+
impl fmt::Display for Ipv4AddrMask {
55+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
56+
write!(fmt, "{}", Ipv4Addr::from_u32(self.mask))
57+
}
58+
}
59+
60+
impl fmt::Debug for Ipv4AddrMask {
61+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
62+
fmt::Display::fmt(self, fmt)
63+
}
64+
}
65+
66+
impl ops::Not for Ipv4AddrMask {
67+
type Output = Ipv4AddrMask;
68+
69+
fn not(self) -> Ipv4AddrMask {
70+
self.invert()
71+
}
72+
}
73+
74+
impl From<Ipv4Addr> for Ipv4AddrMask {
75+
fn from(address: Ipv4Addr) -> Self {
76+
Ipv4AddrMask::from_address(address)
77+
}
78+
}
79+
80+
impl Ipv6AddrMask {
81+
pub const fn from_address(address: Ipv6Addr) -> Ipv6AddrMask {
82+
Ipv6AddrMask { mask: u128::from_be_bytes(address.octets()) }
83+
}
84+
85+
// 32 -> `ffff:ffff::`
86+
pub const fn from_prefix(len: u32) -> Ipv6AddrMask {
87+
let mask = {
88+
if len == 0 {
89+
0
90+
} else {
91+
// shift will not overflow as len > 0, so u128::BITS - len < 128
92+
u128::MAX << (u128::BITS - len)
93+
}
94+
};
95+
96+
Ipv6AddrMask { mask }
97+
}
98+
99+
// 32 -> `0:0:ffff:ffff::ffff:ffff:ffff:fff`
100+
pub const fn from_suffix(len: u32) -> Ipv6AddrMask {
101+
Ipv6AddrMask::from_prefix(len).invert()
102+
}
103+
104+
// `1:2:3:4:5:6:7:8` + `ffff:ffff::` -> `1:2::`
105+
pub const fn apply(&self, address: &Ipv6Addr) -> Ipv6Addr {
106+
let masked = u128::from_be_bytes(address.octets()) & self.mask;
107+
Ipv6Addr::from_u128(masked)
108+
}
109+
110+
// `ffff:ffff::` -> `0:0:ffff:ffff::ffff:ffff:ffff:fff`
111+
pub const fn invert(self) -> Ipv6AddrMask {
112+
Ipv6AddrMask { mask: !self.mask }
113+
}
114+
}
115+
116+
impl fmt::Display for Ipv6AddrMask {
117+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
118+
write!(fmt, "{}", Ipv6Addr::from_u128(self.mask))
119+
}
120+
}
121+
122+
impl fmt::Debug for Ipv6AddrMask {
123+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
124+
fmt::Display::fmt(self, fmt)
125+
}
126+
}
127+
128+
impl ops::Not for Ipv6AddrMask {
129+
type Output = Ipv6AddrMask;
130+
131+
fn not(self) -> Ipv6AddrMask {
132+
self.invert()
133+
}
134+
}
135+
136+
impl From<Ipv6Addr> for Ipv6AddrMask {
137+
fn from(address: Ipv6Addr) -> Self {
138+
Ipv6AddrMask::from_address(address)
139+
}
140+
}

Diff for: library/std/src/net/ip/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ mod tests;
1313
mod network;
1414
pub use self::network::{Ipv4AddrPrefix, Ipv6AddrPrefix};
1515

16+
mod mask;
17+
pub use self::mask::{Ipv4AddrMask, Ipv6AddrMask};
18+
1619
/// An IP address, either IPv4 or IPv6.
1720
///
1821
/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
@@ -767,6 +770,13 @@ impl Ipv4Addr {
767770
}
768771
}
769772

773+
// `1.2.3.4` + `255.255.255.0` -> `1.2.3.0`
774+
#[allow(missing_docs)]
775+
#[unstable(feature = "ip_mask", issue = "none")]
776+
pub const fn mask(&self, mask: Ipv4AddrMask) -> Ipv4Addr {
777+
mask.apply(self)
778+
}
779+
770780
/// Converts this address to an IPv4-compatible [`IPv6` address].
771781
///
772782
/// `a.b.c.d` becomes `::a.b.c.d`
@@ -1484,6 +1494,13 @@ impl Ipv6Addr {
14841494
(self.segments()[0] & 0xff00) == 0xff00
14851495
}
14861496

1497+
// `1:2:3:4:5:6:7:8` + `ffff:ffff::` -> `1:2::`
1498+
#[allow(missing_docs)]
1499+
#[unstable(feature = "ip_mask", issue = "none")]
1500+
pub const fn mask(&self, mask: Ipv6AddrMask) -> Ipv6Addr {
1501+
mask.apply(self)
1502+
}
1503+
14871504
/// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address"
14881505
/// defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
14891506
///

Diff for: library/std/src/net/ip/network.rs

+41-32
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Ipv4Addr, Ipv6Addr};
1+
use super::{Ipv4Addr, Ipv4AddrMask, Ipv6Addr, Ipv6AddrMask};
22
use crate::error::Error;
33
use crate::fmt;
44

@@ -121,13 +121,12 @@ impl Ipv4AddrPrefix {
121121

122122
// Private constructor that assumes len <= 32.
123123
// Useful because `Result::unwrap` is not yet usable in const contexts, so `new` can't be used.
124+
#[unstable(feature = "ip_prefix", issue = "86991")]
124125
pub(crate) const fn new_unchecked(address: Ipv4Addr, len: u32) -> Ipv4AddrPrefix {
125-
let masked = {
126-
let mask = Ipv4AddrPrefix::mask(len);
127-
u32::from_be_bytes(address.octets()) & mask
128-
};
126+
let mask = Ipv4AddrMask::from_prefix(len);
127+
let masked = address.mask(mask);
129128

130-
Ipv4AddrPrefix { address_raw: masked, len: len as u8 }
129+
Ipv4AddrPrefix { address_raw: u32::from_be_bytes(masked.octets()), len: len as u8 }
131130
}
132131

133132
/// Returns the address specifying this address prefix.
@@ -176,15 +175,18 @@ impl Ipv4AddrPrefix {
176175
self.len as u32
177176
}
178177

179-
// Compute the bitmask specified by a prefix length.
180-
#[inline]
181-
const fn mask(len: u32) -> u32 {
182-
if len == 0 {
183-
0
184-
} else {
185-
// shift will not overflow as len > 0, so u32::BITS - len < 32
186-
u32::MAX << (u32::BITS - len)
187-
}
178+
// `192.0.2.0/24` -> `255.255.255.0`
179+
#[allow(missing_docs)]
180+
#[unstable(feature = "ip_mask", issue = "none")]
181+
pub const fn prefix_mask(&self) -> Ipv4AddrMask {
182+
Ipv4AddrMask::from_prefix(self.len as u32)
183+
}
184+
185+
// `192.0.2.0/24` -> `0.0.0.255`
186+
#[allow(missing_docs)]
187+
#[unstable(feature = "ip_mask", issue = "none")]
188+
pub const fn suffix_mask(&self) -> Ipv4AddrMask {
189+
Ipv4AddrMask::from_suffix(self.len as u32)
188190
}
189191

190192
/// Returns `true` if the given address is contained in the network described by this prefix,
@@ -205,8 +207,10 @@ impl Ipv4AddrPrefix {
205207
#[unstable(feature = "ip_prefix", issue = "86991")]
206208
#[inline]
207209
pub const fn contains(&self, address: &Ipv4Addr) -> bool {
208-
let mask = Ipv4AddrPrefix::mask(self.len as u32);
209-
u32::from_be_bytes(address.octets()) & mask == self.address_raw
210+
let mask = self.prefix_mask();
211+
let masked = address.mask(mask);
212+
213+
u32::from_be_bytes(masked.octets()) == self.address_raw
210214
}
211215
}
212216

@@ -259,13 +263,12 @@ impl Ipv6AddrPrefix {
259263

260264
// Private constructor that assumes len <= 128.
261265
// Useful because `Result::unwrap` is not yet usable in const contexts, so `new` can't be used.
266+
#[unstable(feature = "ip_prefix", issue = "86991")]
262267
pub(crate) const fn new_unchecked(address: Ipv6Addr, len: u32) -> Ipv6AddrPrefix {
263-
let masked = {
264-
let mask = Ipv6AddrPrefix::mask(len);
265-
u128::from_be_bytes(address.octets()) & mask
266-
};
268+
let mask = Ipv6AddrMask::from_prefix(len);
269+
let masked = address.mask(mask);
267270

268-
Ipv6AddrPrefix { address_raw: masked, len: len as u8 }
271+
Ipv6AddrPrefix { address_raw: u128::from_be_bytes(masked.octets()), len: len as u8 }
269272
}
270273

271274
/// Returns the address specifying this address prefix.
@@ -313,14 +316,18 @@ impl Ipv6AddrPrefix {
313316
self.len as u32
314317
}
315318

316-
// Compute the bitmask specified by a prefix length.
317-
const fn mask(len: u32) -> u128 {
318-
if len == 0 {
319-
0
320-
} else {
321-
// shift will not overflow as len > 0, so u128::BITS - len < 128
322-
u128::MAX << (u128::BITS - len)
323-
}
319+
// `2001:db8::/32` -> `ffff:ffff::`
320+
#[allow(missing_docs)]
321+
#[unstable(feature = "ip_mask", issue = "none")]
322+
pub const fn prefix_mask(&self) -> Ipv6AddrMask {
323+
Ipv6AddrMask::from_prefix(self.len as u32)
324+
}
325+
326+
// `2001:db8::/32` -> `0:0:ffff:ffff::ffff:ffff:ffff:ffff`
327+
#[allow(missing_docs)]
328+
#[unstable(feature = "ip_mask", issue = "none")]
329+
pub const fn suffix_mask(&self) -> Ipv6AddrMask {
330+
Ipv6AddrMask::from_suffix(self.len as u32)
324331
}
325332

326333
/// Returns `true` if the given address is contained in the network described by this prefix,
@@ -341,8 +348,10 @@ impl Ipv6AddrPrefix {
341348
#[unstable(feature = "ip_prefix", issue = "86991")]
342349
#[inline]
343350
pub const fn contains(&self, address: &Ipv6Addr) -> bool {
344-
let mask = Ipv6AddrPrefix::mask(self.len as u32);
345-
u128::from_be_bytes(address.octets()) & mask == self.address_raw
351+
let mask = self.prefix_mask();
352+
let masked = address.mask(mask);
353+
354+
u128::from_be_bytes(masked.octets()) == self.address_raw
346355
}
347356
}
348357

Diff for: library/std/src/net/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use crate::io::{self, Error, ErrorKind};
2323
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
2424
#[stable(feature = "rust1", since = "1.0.0")]
2525
pub use self::ip::{
26-
IpAddr, Ipv4Addr, Ipv4AddrPrefix, Ipv6Addr, Ipv6AddrPrefix, Ipv6MulticastScope,
26+
IpAddr, Ipv4Addr, Ipv4AddrMask, Ipv4AddrPrefix, Ipv6Addr, Ipv6AddrMask, Ipv6AddrPrefix,
27+
Ipv6MulticastScope,
2728
};
2829
#[stable(feature = "rust1", since = "1.0.0")]
2930
pub use self::parser::AddrParseError;

0 commit comments

Comments
 (0)