Rollup merge of #130629 - Dirbaio:net-from-octets, r=tgross35

core/net: add Ipv[46]Addr::from_octets, Ipv6Addr::from_segments.

Adds:

- `Ipv4Address::from_octets([u8;4])`
- `Ipv6Address::from_octets([u8;16])`
- `Ipv6Address::from_segments([u16;8])`

equivalent to the existing `From` impls.

Advantages:

- Consistent with `to_bits, from_bits`.
- More discoverable than the `From` impls.
- Helps with type inference: it's common to want to convert byte slices to IP addrs. If you try this

```rust
fn foo(x: &[u8]) -> Ipv4Addr {
   Ipv4Addr::from(foo.try_into().unwrap())
}
```

it [doesn't work](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0e2873312de275a58fa6e33d1b213bec). You have to write `Ipv4Addr::from(<[u8;4]>::try_from(x).unwrap())` instead, which is not great. With `from_octets` it is able to infer the right types.

Found this while porting [smoltcp](https://github.com/smoltcp-rs/smoltcp/) from its own IP address types to the `core::net` types.

~~Tracking issues #27709 #76205~~
Tracking issue: https://github.com/rust-lang/rust/issues/131360
This commit is contained in:
Matthias Krüger 2024-10-14 06:04:27 +02:00 committed by GitHub
commit e01eae72da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 114 additions and 26 deletions

View File

@ -600,6 +600,24 @@ pub const fn from_bits(bits: u32) -> Ipv4Addr {
self.octets
}
/// Creates an `Ipv4Addr` from a four element byte array.
///
/// # Examples
///
/// ```
/// #![feature(ip_from)]
/// use std::net::Ipv4Addr;
///
/// let addr = Ipv4Addr::from_octets([13u8, 12u8, 11u8, 10u8]);
/// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
/// ```
#[unstable(feature = "ip_from", issue = "131360")]
#[must_use]
#[inline]
pub const fn from_octets(octets: [u8; 4]) -> Ipv4Addr {
Ipv4Addr { octets }
}
/// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
///
/// This property is defined in _UNIX Network Programming, Second Edition_,
@ -1400,6 +1418,34 @@ pub const fn from_bits(bits: u128) -> Ipv6Addr {
]
}
/// Creates an `Ipv6Addr` from an eight element 16-bit array.
///
/// # Examples
///
/// ```
/// #![feature(ip_from)]
/// use std::net::Ipv6Addr;
///
/// let addr = Ipv6Addr::from_segments([
/// 0x20du16, 0x20cu16, 0x20bu16, 0x20au16,
/// 0x209u16, 0x208u16, 0x207u16, 0x206u16,
/// ]);
/// assert_eq!(
/// Ipv6Addr::new(
/// 0x20d, 0x20c, 0x20b, 0x20a,
/// 0x209, 0x208, 0x207, 0x206,
/// ),
/// addr
/// );
/// ```
#[unstable(feature = "ip_from", issue = "131360")]
#[must_use]
#[inline]
pub const fn from_segments(segments: [u16; 8]) -> Ipv6Addr {
let [a, b, c, d, e, f, g, h] = segments;
Ipv6Addr::new(a, b, c, d, e, f, g, h)
}
/// Returns [`true`] for the special 'unspecified' address (`::`).
///
/// This property is defined in [IETF RFC 4291].
@ -1932,7 +1978,7 @@ pub const fn to_canonical(&self) -> IpAddr {
/// use std::net::Ipv6Addr;
///
/// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
/// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
/// [0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
/// ```
#[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
#[stable(feature = "ipv6_to_octets", since = "1.12.0")]
@ -1941,6 +1987,33 @@ pub const fn to_canonical(&self) -> IpAddr {
pub const fn octets(&self) -> [u8; 16] {
self.octets
}
/// Creates an `Ipv6Addr` from a sixteen element byte array.
///
/// # Examples
///
/// ```
/// #![feature(ip_from)]
/// use std::net::Ipv6Addr;
///
/// let addr = Ipv6Addr::from_octets([
/// 0x19u8, 0x18u8, 0x17u8, 0x16u8, 0x15u8, 0x14u8, 0x13u8, 0x12u8,
/// 0x11u8, 0x10u8, 0x0fu8, 0x0eu8, 0x0du8, 0x0cu8, 0x0bu8, 0x0au8,
/// ]);
/// assert_eq!(
/// Ipv6Addr::new(
/// 0x1918, 0x1716, 0x1514, 0x1312,
/// 0x1110, 0x0f0e, 0x0d0c, 0x0b0a,
/// ),
/// addr
/// );
/// ```
#[unstable(feature = "ip_from", issue = "131360")]
#[must_use]
#[inline]
pub const fn from_octets(octets: [u8; 16]) -> Ipv6Addr {
Ipv6Addr { octets }
}
}
/// Writes an Ipv6Addr, conforming to the canonical style described by
@ -2113,15 +2186,13 @@ fn from(ip: u128) -> Ipv6Addr {
/// use std::net::Ipv6Addr;
///
/// let addr = Ipv6Addr::from([
/// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
/// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
/// 0x19u8, 0x18u8, 0x17u8, 0x16u8, 0x15u8, 0x14u8, 0x13u8, 0x12u8,
/// 0x11u8, 0x10u8, 0x0fu8, 0x0eu8, 0x0du8, 0x0cu8, 0x0bu8, 0x0au8,
/// ]);
/// assert_eq!(
/// Ipv6Addr::new(
/// 0x1918, 0x1716,
/// 0x1514, 0x1312,
/// 0x1110, 0x0f0e,
/// 0x0d0c, 0x0b0a
/// 0x1918, 0x1716, 0x1514, 0x1312,
/// 0x1110, 0x0f0e, 0x0d0c, 0x0b0a,
/// ),
/// addr
/// );
@ -2142,15 +2213,13 @@ fn from(ip: u128) -> Ipv6Addr {
/// use std::net::Ipv6Addr;
///
/// let addr = Ipv6Addr::from([
/// 525u16, 524u16, 523u16, 522u16,
/// 521u16, 520u16, 519u16, 518u16,
/// 0x20du16, 0x20cu16, 0x20bu16, 0x20au16,
/// 0x209u16, 0x208u16, 0x207u16, 0x206u16,
/// ]);
/// assert_eq!(
/// Ipv6Addr::new(
/// 0x20d, 0x20c,
/// 0x20b, 0x20a,
/// 0x209, 0x208,
/// 0x207, 0x206
/// 0x20d, 0x20c, 0x20b, 0x20a,
/// 0x209, 0x208, 0x207, 0x206,
/// ),
/// addr
/// );
@ -2172,15 +2241,13 @@ fn from(ip: u128) -> Ipv6Addr {
/// use std::net::{IpAddr, Ipv6Addr};
///
/// let addr = IpAddr::from([
/// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
/// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
/// 0x19u8, 0x18u8, 0x17u8, 0x16u8, 0x15u8, 0x14u8, 0x13u8, 0x12u8,
/// 0x11u8, 0x10u8, 0x0fu8, 0x0eu8, 0x0du8, 0x0cu8, 0x0bu8, 0x0au8,
/// ]);
/// assert_eq!(
/// IpAddr::V6(Ipv6Addr::new(
/// 0x1918, 0x1716,
/// 0x1514, 0x1312,
/// 0x1110, 0x0f0e,
/// 0x0d0c, 0x0b0a
/// 0x1918, 0x1716, 0x1514, 0x1312,
/// 0x1110, 0x0f0e, 0x0d0c, 0x0b0a,
/// )),
/// addr
/// );
@ -2201,15 +2268,13 @@ fn from(ip: u128) -> Ipv6Addr {
/// use std::net::{IpAddr, Ipv6Addr};
///
/// let addr = IpAddr::from([
/// 525u16, 524u16, 523u16, 522u16,
/// 521u16, 520u16, 519u16, 518u16,
/// 0x20du16, 0x20cu16, 0x20bu16, 0x20au16,
/// 0x209u16, 0x208u16, 0x207u16, 0x206u16,
/// ]);
/// assert_eq!(
/// IpAddr::V6(Ipv6Addr::new(
/// 0x20d, 0x20c,
/// 0x20b, 0x20a,
/// 0x209, 0x208,
/// 0x207, 0x206
/// 0x20d, 0x20c, 0x20b, 0x20a,
/// 0x209, 0x208, 0x207, 0x206,
/// )),
/// addr
/// );

View File

@ -50,6 +50,7 @@
#![feature(hashmap_internals)]
#![feature(int_roundings)]
#![feature(ip)]
#![feature(ip_from)]
#![feature(is_ascii_octdigit)]
#![feature(isqrt)]
#![feature(iter_advance_by)]

View File

@ -494,6 +494,7 @@ macro_rules! check {
let octets = &[$($octet),*];
assert_eq!(&ip!($s).octets(), octets);
assert_eq!(Ipv6Addr::from(*octets), ip!($s));
assert_eq!(Ipv6Addr::from_octets(*octets), ip!($s));
let unspecified: u32 = 1 << 0;
let loopback: u32 = 1 << 1;
@ -846,15 +847,19 @@ fn ipv6_from_constructors() {
#[test]
fn ipv4_from_octets() {
assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1));
assert_eq!(Ipv4Addr::from_octets([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1));
}
#[test]
fn ipv6_from_segments() {
let from_u16s =
Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
let from_u16s_explicit =
Ipv6Addr::from_segments([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
assert_eq!(new, from_u16s);
assert_eq!(new, from_u16s_explicit);
}
#[test]
@ -865,7 +870,15 @@ fn ipv6_from_octets() {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
0xff,
]);
let from_u16s_explicit =
Ipv6Addr::from_segments([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
let from_u8s_explicit = Ipv6Addr::from_octets([
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
0xff,
]);
assert_eq!(from_u16s, from_u8s);
assert_eq!(from_u16s, from_u16s_explicit);
assert_eq!(from_u16s_explicit, from_u8s_explicit);
}
#[test]
@ -915,6 +928,9 @@ fn ipv4_const() {
const OCTETS: [u8; 4] = IP_ADDRESS.octets();
assert_eq!(OCTETS, [127, 0, 0, 1]);
const FROM_OCTETS: Ipv4Addr = Ipv4Addr::from_octets(OCTETS);
assert_eq!(IP_ADDRESS, FROM_OCTETS);
const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
assert!(!IS_UNSPECIFIED);
@ -971,9 +987,15 @@ fn ipv6_const() {
const SEGMENTS: [u16; 8] = IP_ADDRESS.segments();
assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]);
const FROM_SEGMENTS: Ipv6Addr = Ipv6Addr::from_segments(SEGMENTS);
assert_eq!(IP_ADDRESS, FROM_SEGMENTS);
const OCTETS: [u8; 16] = IP_ADDRESS.octets();
assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
const FROM_OCTETS: Ipv6Addr = Ipv6Addr::from_octets(OCTETS);
assert_eq!(IP_ADDRESS, FROM_OCTETS);
const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
assert!(!IS_UNSPECIFIED);