Skip to content

Commit 02f141c

Browse files
committed
Add FromStr implementation to Ipv{v,6}AddrPrefix
1 parent 0a8b944 commit 02f141c

File tree

2 files changed

+126
-4
lines changed

2 files changed

+126
-4
lines changed

library/std/src/net/ip/tests.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,68 @@ fn test_from_str_socket_addr() {
108108
assert_eq!(None, none);
109109
}
110110

111+
#[test]
112+
fn test_from_str_ipv4_prefix() {
113+
assert_eq!(
114+
Ok(Ipv4AddrPrefix::new_unchecked(Ipv4Addr::new(127, 0, 0, 1), 16)),
115+
"127.0.0.1/16".parse()
116+
);
117+
assert_eq!(
118+
Ok(Ipv4AddrPrefix::new_unchecked(Ipv4Addr::new(255, 255, 255, 255), 32)),
119+
"255.255.255.255/32".parse()
120+
);
121+
assert_eq!(
122+
Ok(Ipv4AddrPrefix::new_unchecked(Ipv4Addr::new(0, 0, 0, 0), 0)),
123+
"0.0.0.0/0".parse()
124+
);
125+
126+
// no prefix
127+
let none: Option<Ipv4AddrPrefix> = "255.0.0.1".parse().ok();
128+
assert_eq!(None, none);
129+
// wrong prefix separator
130+
let none: Option<Ipv4AddrPrefix> = "255.0.0.1:16".parse().ok();
131+
assert_eq!(None, none);
132+
// prefix can not be longer than 32 bits
133+
let none: Option<Ipv4AddrPrefix> = "255.0.0.1/35".parse().ok();
134+
assert_eq!(None, none);
135+
}
136+
137+
#[test]
138+
fn test_from_str_ipv6_prefix() {
139+
assert_eq!(
140+
Ok(Ipv6AddrPrefix::new_unchecked(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 0)),
141+
"0:0:0:0:0:0:0:0/0".parse()
142+
);
143+
assert_eq!(
144+
Ok(Ipv6AddrPrefix::new_unchecked(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 128)),
145+
"0:0:0:0:0:0:0:1/128".parse()
146+
);
147+
148+
assert_eq!(
149+
Ok(Ipv6AddrPrefix::new_unchecked(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 128)),
150+
"::1/128".parse()
151+
);
152+
assert_eq!(
153+
Ok(Ipv6AddrPrefix::new_unchecked(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 0)),
154+
"::/0".parse()
155+
);
156+
157+
assert_eq!(
158+
Ok(Ipv6AddrPrefix::new_unchecked(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11), 32)),
159+
"2a02:6b8::11:11/32".parse()
160+
);
161+
162+
// no prefix
163+
let none: Option<Ipv6AddrPrefix> = "1:2:3:4::5:6:7:8".parse().ok();
164+
assert_eq!(None, none);
165+
// wrong prefix separator
166+
let none: Option<Ipv6AddrPrefix> = "1:2:3:4::5:6:7:8:16".parse().ok();
167+
assert_eq!(None, none);
168+
// prefix can not be longer than 128 bits
169+
let none: Option<Ipv6AddrPrefix> = "1:2:3:4::5:6:7:8/130".parse().ok();
170+
assert_eq!(None, none);
171+
}
172+
111173
#[test]
112174
fn ipv4_addr_to_string() {
113175
assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
@@ -171,6 +233,19 @@ fn ipv6_addr_to_string() {
171233
assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)));
172234
}
173235

236+
#[test]
237+
fn ip_prefix_to_string() {
238+
assert_eq!(
239+
Ipv4AddrPrefix::new_unchecked(Ipv4Addr::new(127, 0, 0, 1), 24).to_string(),
240+
"127.0.0.0/24"
241+
);
242+
assert_eq!(
243+
Ipv6AddrPrefix::new_unchecked(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7F00, 1), 96)
244+
.to_string(),
245+
"::ffff:0.0.0.0/96"
246+
);
247+
}
248+
174249
#[test]
175250
fn ipv4_to_ipv6() {
176251
assert_eq!(

library/std/src/net/parser.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ mod tests;
99
use crate::convert::TryInto as _;
1010
use crate::error::Error;
1111
use crate::fmt;
12-
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
12+
use crate::net::{
13+
IpAddr, Ipv4Addr, Ipv4AddrPrefix, Ipv6Addr, Ipv6AddrPrefix, SocketAddr, SocketAddrV4,
14+
SocketAddrV6,
15+
};
1316
use crate::str::FromStr;
1417

1518
trait ReadNumberHelper: crate::marker::Sized {
@@ -231,6 +234,16 @@ impl<'a> Parser<'a> {
231234
})
232235
}
233236

237+
/// Read a `/` followed by a prefix length in base 10.
238+
fn read_prefix(&mut self, max: u32) -> Option<u32> {
239+
self.read_atomically(|p| {
240+
p.read_given_char('/')?;
241+
let len = p.read_number(10, None)?;
242+
243+
if len <= max { Some(len) } else { None }
244+
})
245+
}
246+
234247
/// Read a `%` followed by a scope ID in base 10.
235248
fn read_scope_id(&mut self) -> Option<u32> {
236249
self.read_atomically(|p| {
@@ -267,6 +280,24 @@ impl<'a> Parser<'a> {
267280
.map(SocketAddr::V4)
268281
.or_else(|| self.read_socket_addr_v6().map(SocketAddr::V6))
269282
}
283+
284+
/// Read an IPv4 address prefix; an address followed by a prefix length
285+
fn read_addr_v4_prefix(&mut self) -> Option<Ipv4AddrPrefix> {
286+
self.read_atomically(|p| {
287+
let address = p.read_ipv4_addr()?;
288+
let len = p.read_prefix(u32::BITS)?;
289+
Some(Ipv4AddrPrefix::new_unchecked(address, len))
290+
})
291+
}
292+
293+
/// Read an IPv6 address prefix; an address followed by a prefix length
294+
fn read_addr_v6_prefix(&mut self) -> Option<Ipv6AddrPrefix> {
295+
self.read_atomically(|p| {
296+
let address = p.read_ipv6_addr()?;
297+
let len = p.read_prefix(u128::BITS)?;
298+
Some(Ipv6AddrPrefix::new_unchecked(address, len))
299+
})
300+
}
270301
}
271302

272303
#[stable(feature = "ip_addr", since = "1.7.0")]
@@ -317,11 +348,27 @@ impl FromStr for SocketAddr {
317348
}
318349
}
319350

320-
/// An error which can be returned when parsing an IP address or a socket address.
351+
#[unstable(feature = "ip_prefix", issue = "86991")]
352+
impl FromStr for Ipv4AddrPrefix {
353+
type Err = AddrParseError;
354+
fn from_str(s: &str) -> Result<Ipv4AddrPrefix, AddrParseError> {
355+
Parser::new(s).parse_with(|p| p.read_addr_v4_prefix())
356+
}
357+
}
358+
359+
#[unstable(feature = "ip_prefix", issue = "86991")]
360+
impl FromStr for Ipv6AddrPrefix {
361+
type Err = AddrParseError;
362+
fn from_str(s: &str) -> Result<Ipv6AddrPrefix, AddrParseError> {
363+
Parser::new(s).parse_with(|p| p.read_addr_v6_prefix())
364+
}
365+
}
366+
367+
/// An error which can be returned when parsing an IP address, IP address prefix or a socket address.
321368
///
322369
/// This error is used as the error type for the [`FromStr`] implementation for
323-
/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and
324-
/// [`SocketAddrV6`].
370+
/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`Ipv4AddrPrefix`], [`Ipv6AddrPrefix`],
371+
/// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`].
325372
///
326373
/// # Potential causes
327374
///

0 commit comments

Comments
 (0)