about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2020-08-11 16:23:45 +0900
committerGitHub <noreply@github.com>2020-08-11 16:23:45 +0900
commitf26f201d42df2a42124383eafaa23eb97f620718 (patch)
tree59a9e47f0e7fa1eddeeb1c5513b2d6998ea632c8
parentfa853f3df0ec7b9bf86770bda85f764e9791e4ac (diff)
parent0210fd3d7303a626f6e821bde8fdfea056cc043b (diff)
downloadrust-f26f201d42df2a42124383eafaa23eb97f620718.tar.gz
rust-f26f201d42df2a42124383eafaa23eb97f620718.zip
Rollup merge of #75085 - lzutao:ip_union, r=cuviper
Transmute big endian `s6_addr` and `[u16; 8]`

The old code already made the assumption to reinterpret
`Ipv6Addr` as `[u16; 8]`.

Glibc, Linux, FreeBSD, Win32 all makes this assumption.
The main motivation of using union it to better optimize code.
Godbolt: https://rust.godbolt.org/z/b4bGvo
Const is introducing unsafe when transmuting.

ref:
* https://docs.microsoft.com/en-us/windows/win32/api/in6addr/ns-in6addr-in6_addr
* https://github.com/freebsd/freebsd/blob/1d6e4247415d264485ee94b59fdbc12e0c566fd0/contrib/ntp/lib/isc/include/isc/ipv6.h#L63
* https://github.com/zephyrproject-rtos/zephyr/blob/8b531aa996bba254c03129658490af59597acd78/include/net/net_ip.h#L137
* https://sourceware.org/git/?p=glibc.git;a=blob;f=inet/netinet/in.h;h=f6355c7efe5192b88337b136ef687fe9a5ed648c;hb=HEAD#l216
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/net/ip.rs54
2 files changed, 28 insertions, 27 deletions
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 0569e46241a..f0487e0dff1 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -249,6 +249,7 @@
 #![feature(clamp)]
 #![feature(concat_idents)]
 #![feature(const_cstr_unchecked)]
+#![feature(const_fn_transmute)]
 #![feature(const_raw_ptr_deref)]
 #![feature(container_error_extra)]
 #![feature(core_intrinsics)]
diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index 159ab981b23..5d103e64037 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -10,6 +10,7 @@ use crate::cmp::Ordering;
 use crate::fmt::{self, Write as FmtWrite};
 use crate::hash;
 use crate::io::Write as IoWrite;
+use crate::mem::transmute;
 use crate::sys::net::netc as c;
 use crate::sys_common::{AsInner, FromInner};
 
@@ -1045,27 +1046,23 @@ impl Ipv6Addr {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
+    #[allow_internal_unstable(const_fn_transmute)]
     pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
+        let addr16 = [
+            a.to_be(),
+            b.to_be(),
+            c.to_be(),
+            d.to_be(),
+            e.to_be(),
+            f.to_be(),
+            g.to_be(),
+            h.to_be(),
+        ];
         Ipv6Addr {
             inner: c::in6_addr {
-                s6_addr: [
-                    (a >> 8) as u8,
-                    a as u8,
-                    (b >> 8) as u8,
-                    b as u8,
-                    (c >> 8) as u8,
-                    c as u8,
-                    (d >> 8) as u8,
-                    d as u8,
-                    (e >> 8) as u8,
-                    e as u8,
-                    (f >> 8) as u8,
-                    f as u8,
-                    (g >> 8) as u8,
-                    g as u8,
-                    (h >> 8) as u8,
-                    h as u8,
-                ],
+                // All elements in `addr16` are big endian.
+                // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
+                s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) },
             },
         }
     }
@@ -1108,16 +1105,19 @@ impl Ipv6Addr {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn segments(&self) -> [u16; 8] {
-        let arr = &self.inner.s6_addr;
+        // All elements in `s6_addr` must be big endian.
+        // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
+        let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) };
+        // We want native endian u16
         [
-            u16::from_be_bytes([arr[0], arr[1]]),
-            u16::from_be_bytes([arr[2], arr[3]]),
-            u16::from_be_bytes([arr[4], arr[5]]),
-            u16::from_be_bytes([arr[6], arr[7]]),
-            u16::from_be_bytes([arr[8], arr[9]]),
-            u16::from_be_bytes([arr[10], arr[11]]),
-            u16::from_be_bytes([arr[12], arr[13]]),
-            u16::from_be_bytes([arr[14], arr[15]]),
+            u16::from_be(a),
+            u16::from_be(b),
+            u16::from_be(c),
+            u16::from_be(d),
+            u16::from_be(e),
+            u16::from_be(f),
+            u16::from_be(g),
+            u16::from_be(h),
         ]
     }