From ba620344301aaa3b2733575a0696cdfd877edbdf Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Sat, 10 Aug 2024 23:52:35 +0200 Subject: [PATCH 1/3] Hash Ipv*Addr as an integer --- library/core/src/net/ip_addr.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 3e036b88128..6dc8018d80d 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1,6 +1,7 @@ use super::display_buffer::DisplayBuffer; use crate::cmp::Ordering; use crate::fmt::{self, Write}; +use crate::hash::{Hash, Hasher}; use crate::iter; use crate::mem::transmute; use crate::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not}; @@ -67,12 +68,20 @@ pub enum IpAddr { /// assert!("0000000.0.0.0".parse::().is_err()); // first octet is a zero in octal /// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv4Addr { octets: [u8; 4], } +impl Hash for Ipv4Addr { + fn hash(&self, state: &mut H) { + // Hashers are often more efficient at hashing a fixed-width integer + // than a bytestring, so convert before hashing. + u32::from_le_bytes(self.octets).hash(state); + } +} + /// An IPv6 address. /// /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. @@ -149,12 +158,20 @@ pub struct Ipv4Addr { /// assert_eq!("::1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); /// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { octets: [u8; 16], } +impl Hash for Ipv6Addr { + fn hash(&self, state: &mut H) { + // Hashers are often more efficient at hashing a fixed-width integer + // than a bytestring, so convert before hashing. + u128::from_le_bytes(self.octets).hash(state); + } +} + /// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. /// /// # Stability Guarantees From a04a1e464f6c83e1472d3b20141fabd631a5c178 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Sun, 11 Aug 2024 01:28:30 +0200 Subject: [PATCH 2/3] Fix stability annotation and expand comment --- library/core/src/net/ip_addr.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 6dc8018d80d..495e9ade383 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -74,10 +74,13 @@ pub struct Ipv4Addr { octets: [u8; 4], } +#[stable(feature = "rust1", since = "1.0.0")] impl Hash for Ipv4Addr { fn hash(&self, state: &mut H) { // Hashers are often more efficient at hashing a fixed-width integer - // than a bytestring, so convert before hashing. + // than a bytestring, so convert before hashing. We don't use to_bits() + // here as that involves a byteswap on little-endian machines, which are + // more common than big-endian machines. u32::from_le_bytes(self.octets).hash(state); } } @@ -164,10 +167,13 @@ pub struct Ipv6Addr { octets: [u8; 16], } +#[stable(feature = "rust1", since = "1.0.0")] impl Hash for Ipv6Addr { fn hash(&self, state: &mut H) { // Hashers are often more efficient at hashing a fixed-width integer - // than a bytestring, so convert before hashing. + // than a bytestring, so convert before hashing. We don't use to_bits() + // here as that involves byteswaps on little-endian machines, which are + // more common than big-endian machines. u128::from_le_bytes(self.octets).hash(state); } } From fce1decc3c6508aa72f590d024e583dd5c0cf04d Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Sun, 11 Aug 2024 14:55:29 +0200 Subject: [PATCH 3/3] Do not use unnecessary endian conversion. --- library/core/src/net/ip_addr.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 495e9ade383..919f681f911 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -79,9 +79,8 @@ impl Hash for Ipv4Addr { fn hash(&self, state: &mut H) { // Hashers are often more efficient at hashing a fixed-width integer // than a bytestring, so convert before hashing. We don't use to_bits() - // here as that involves a byteswap on little-endian machines, which are - // more common than big-endian machines. - u32::from_le_bytes(self.octets).hash(state); + // here as that may involve a byteswap which is unnecessary. + u32::from_ne_bytes(self.octets).hash(state); } } @@ -172,9 +171,8 @@ impl Hash for Ipv6Addr { fn hash(&self, state: &mut H) { // Hashers are often more efficient at hashing a fixed-width integer // than a bytestring, so convert before hashing. We don't use to_bits() - // here as that involves byteswaps on little-endian machines, which are - // more common than big-endian machines. - u128::from_le_bytes(self.octets).hash(state); + // here as that may involve unnecessary byteswaps. + u128::from_ne_bytes(self.octets).hash(state); } }