about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-10-14 06:04:27 +0200
committerGitHub <noreply@github.com>2024-10-14 06:04:27 +0200
commite01eae72daff6e7931d4aa05250480e404f15efc (patch)
tree4c78ef771fe8e8e098480139783a94c539a7cee5
parent55f8b9e7d8847bf744756513570fd60a24a14760 (diff)
parent0b7e39908ee6314dd8b8561dd4c8a47ce3ba2f38 (diff)
downloadrust-e01eae72daff6e7931d4aa05250480e404f15efc.tar.gz
rust-e01eae72daff6e7931d4aa05250480e404f15efc.zip
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
-rw-r--r--library/core/src/net/ip_addr.rs115
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/net/ip_addr.rs24
3 files changed, 114 insertions, 26 deletions
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index 919f681f911..05e1f3ee7a2 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -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_,
@@ -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].
@@ -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")]
@@ -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
@@ -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
     /// );
@@ -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
     /// );
@@ -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
     /// );
@@ -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
     /// );
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 9e15bb1dd8f..4e1000e1df0 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -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)]
diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs
index a10b51c550d..707f9a160e1 100644
--- a/library/core/tests/net/ip_addr.rs
+++ b/library/core/tests/net/ip_addr.rs
@@ -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;
@@ -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);