Skip to content

Commit 0210fd3

Browse files
tesujicuviperretep998
committed
Transmute between 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. 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 Co-authored-by: Josh Stone <cuviper@gmail.com> Co-authored-by: Peter Atashian <retep998@gmail.com>
1 parent f5fef3c commit 0210fd3

File tree

2 files changed

+28
-27
lines changed

2 files changed

+28
-27
lines changed

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@
249249
#![feature(clamp)]
250250
#![feature(concat_idents)]
251251
#![feature(const_cstr_unchecked)]
252+
#![feature(const_fn_transmute)]
252253
#![feature(const_raw_ptr_deref)]
253254
#![feature(container_error_extra)]
254255
#![feature(core_intrinsics)]

library/std/src/net/ip.rs

+27-27
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::cmp::Ordering;
1010
use crate::fmt::{self, Write as FmtWrite};
1111
use crate::hash;
1212
use crate::io::Write as IoWrite;
13+
use crate::mem::transmute;
1314
use crate::sys::net::netc as c;
1415
use crate::sys_common::{AsInner, FromInner};
1516

@@ -1045,27 +1046,23 @@ impl Ipv6Addr {
10451046
/// ```
10461047
#[stable(feature = "rust1", since = "1.0.0")]
10471048
#[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
1049+
#[allow_internal_unstable(const_fn_transmute)]
10481050
pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
1051+
let addr16 = [
1052+
a.to_be(),
1053+
b.to_be(),
1054+
c.to_be(),
1055+
d.to_be(),
1056+
e.to_be(),
1057+
f.to_be(),
1058+
g.to_be(),
1059+
h.to_be(),
1060+
];
10491061
Ipv6Addr {
10501062
inner: c::in6_addr {
1051-
s6_addr: [
1052-
(a >> 8) as u8,
1053-
a as u8,
1054-
(b >> 8) as u8,
1055-
b as u8,
1056-
(c >> 8) as u8,
1057-
c as u8,
1058-
(d >> 8) as u8,
1059-
d as u8,
1060-
(e >> 8) as u8,
1061-
e as u8,
1062-
(f >> 8) as u8,
1063-
f as u8,
1064-
(g >> 8) as u8,
1065-
g as u8,
1066-
(h >> 8) as u8,
1067-
h as u8,
1068-
],
1063+
// All elements in `addr16` are big endian.
1064+
// SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
1065+
s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) },
10691066
},
10701067
}
10711068
}
@@ -1108,16 +1105,19 @@ impl Ipv6Addr {
11081105
/// ```
11091106
#[stable(feature = "rust1", since = "1.0.0")]
11101107
pub fn segments(&self) -> [u16; 8] {
1111-
let arr = &self.inner.s6_addr;
1108+
// All elements in `s6_addr` must be big endian.
1109+
// SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
1110+
let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) };
1111+
// We want native endian u16
11121112
[
1113-
u16::from_be_bytes([arr[0], arr[1]]),
1114-
u16::from_be_bytes([arr[2], arr[3]]),
1115-
u16::from_be_bytes([arr[4], arr[5]]),
1116-
u16::from_be_bytes([arr[6], arr[7]]),
1117-
u16::from_be_bytes([arr[8], arr[9]]),
1118-
u16::from_be_bytes([arr[10], arr[11]]),
1119-
u16::from_be_bytes([arr[12], arr[13]]),
1120-
u16::from_be_bytes([arr[14], arr[15]]),
1113+
u16::from_be(a),
1114+
u16::from_be(b),
1115+
u16::from_be(c),
1116+
u16::from_be(d),
1117+
u16::from_be(e),
1118+
u16::from_be(f),
1119+
u16::from_be(g),
1120+
u16::from_be(h),
11211121
]
11221122
}
11231123

0 commit comments

Comments
 (0)