Skip to content

Commit

Permalink
Rollup merge of #130629 - Dirbaio:net-from-octets, r=tgross35
Browse files Browse the repository at this point in the history
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: #131360
  • Loading branch information
matthiaskrgr authored Oct 14, 2024
2 parents 55f8b9e + 0b7e399 commit e01eae7
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 26 deletions.
115 changes: 90 additions & 25 deletions library/core/src/net/ip_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,24 @@ impl 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_,
Expand Down Expand Up @@ -1400,6 +1418,34 @@ impl 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].
Expand Down Expand Up @@ -1932,7 +1978,7 @@ impl Ipv6Addr {
/// 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")]
Expand All @@ -1941,6 +1987,33 @@ impl Ipv6Addr {
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
Expand Down Expand Up @@ -2113,15 +2186,13 @@ impl From<[u8; 16]> for 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
/// );
Expand All @@ -2142,15 +2213,13 @@ impl From<[u16; 8]> for 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
/// );
Expand All @@ -2172,15 +2241,13 @@ impl From<[u8; 16]> for IpAddr {
/// 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
/// );
Expand All @@ -2201,15 +2268,13 @@ impl From<[u16; 8]> for IpAddr {
/// 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
/// );
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
24 changes: 23 additions & 1 deletion library/core/tests/net/ip_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ fn ipv6_properties() {
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;
Expand Down Expand Up @@ -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]
Expand All @@ -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]
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit e01eae7

Please sign in to comment.