about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-06-25 06:47:30 +0000
committerbors <bors@rust-lang.org>2021-06-25 06:47:30 +0000
commit50e0cc59ffcacda5b48f4edb95e5a5c353624fb0 (patch)
treee439eaa42d3072e2b5882ca004fb696aa8742583
parent50a908121620edbef02d124e8d7d94943c50d4a1 (diff)
parent579d19bc6ac91548e8b256656ca1d7fbceb53197 (diff)
downloadrust-50e0cc59ffcacda5b48f4edb95e5a5c353624fb0.tar.gz
rust-50e0cc59ffcacda5b48f4edb95e5a5c353624fb0.zip
Auto merge of #86151 - scottmcm:simple-hash-of, r=joshtriplett
Add `BuildHasher::hash_one` as unstable

Inspired by https://github.com/rust-lang/rust/pull/86140/files#diff-246941135168fbc44fce120385ee9c3156e08a1c3e2697985b56dcb8d728eedeR2416, where I wanted to write a quick test for a `Hash` implementation and it took more of a dance than I'd hoped.

It looks like this would be handy in hashtable implementations, too -- a quick look at hashbrown found two places where it needs to do the same dance:
https://github.com/rust-lang/hashbrown/blob/6302512a8a514fe5bd442464ebcd78139c82e1e2/src/map.rs#L247-L270

I wanted to get a "seems plausible" from a libs member before making a tracking issue, so random-sampling the intersection of highfive and governance gave me...
r? `@joshtriplett`

(As always, bikeshed away!  And let me know if I missed something obvious again that I should have used instead.)
-rw-r--r--library/alloc/src/vec/mod.rs11
-rw-r--r--library/core/src/array/mod.rs11
-rw-r--r--library/core/src/hash/mod.rs44
3 files changed, 50 insertions, 16 deletions
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index f3a47cba759..4ac28b8308e 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2411,18 +2411,13 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
 /// as required by the `core::borrow::Borrow` implementation.
 ///
 /// ```
-/// use std::hash::{BuildHasher, Hash, Hasher};
-///
-/// fn hash_of(x: impl Hash, b: &impl BuildHasher) -> u64 {
-///     let mut h = b.build_hasher();
-///     x.hash(&mut h);
-///     h.finish()
-/// }
+/// #![feature(build_hasher_simple_hash_one)]
+/// use std::hash::BuildHasher;
 ///
 /// let b = std::collections::hash_map::RandomState::new();
 /// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09];
 /// let s: &[u8] = &[0xa8, 0x3c, 0x09];
-/// assert_eq!(hash_of(v, &b), hash_of(s, &b));
+/// assert_eq!(b.hash_one(v), b.hash_one(s));
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Hash, A: Allocator> Hash for Vec<T, A> {
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index f44e22b3dbd..030b42a53d0 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -143,18 +143,13 @@ impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] {
 /// as required by the `Borrow` implementation.
 ///
 /// ```
-/// use std::hash::{BuildHasher, Hash, Hasher};
-///
-/// fn hash_of(x: impl Hash, b: &impl BuildHasher) -> u64 {
-///     let mut h = b.build_hasher();
-///     x.hash(&mut h);
-///     h.finish()
-/// }
+/// #![feature(build_hasher_simple_hash_one)]
+/// use std::hash::BuildHasher;
 ///
 /// let b = std::collections::hash_map::RandomState::new();
 /// let a: [u8; 3] = [0xa8, 0x3c, 0x09];
 /// let s: &[u8] = &[0xa8, 0x3c, 0x09];
-/// assert_eq!(hash_of(a, &b), hash_of(s, &b));
+/// assert_eq!(b.hash_one(a), b.hash_one(s));
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Hash, const N: usize> Hash for [T; N] {
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 77d3a35b268..9dbefe0822e 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -481,6 +481,50 @@ pub trait BuildHasher {
     /// ```
     #[stable(since = "1.7.0", feature = "build_hasher")]
     fn build_hasher(&self) -> Self::Hasher;
+
+    /// Calculates the hash of a single value.
+    ///
+    /// This is intended as a convenience for code which *consumes* hashes, such
+    /// as the implementation of a hash table or in unit tests that check
+    /// whether a custom [`Hash`] implementation behaves as expected.
+    ///
+    /// This must not be used in any code which *creates* hashes, such as in an
+    /// implementation of [`Hash`].  The way to create a combined hash of
+    /// multiple values is to call [`Hash::hash`] multiple times using the same
+    /// [`Hasher`], not to call this method repeatedly and combine the results.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(build_hasher_simple_hash_one)]
+    ///
+    /// use std::cmp::{max, min};
+    /// use std::hash::{BuildHasher, Hash, Hasher};
+    /// struct OrderAmbivalentPair<T: Ord>(T, T);
+    /// impl<T: Ord + Hash> Hash for OrderAmbivalentPair<T> {
+    ///     fn hash<H: Hasher>(&self, hasher: &mut H) {
+    ///         min(&self.0, &self.1).hash(hasher);
+    ///         max(&self.0, &self.1).hash(hasher);
+    ///     }
+    /// }
+    ///
+    /// // Then later, in a `#[test]` for the type...
+    /// let bh = std::collections::hash_map::RandomState::new();
+    /// assert_eq!(
+    ///     bh.hash_one(OrderAmbivalentPair(1, 2)),
+    ///     bh.hash_one(OrderAmbivalentPair(2, 1))
+    /// );
+    /// assert_eq!(
+    ///     bh.hash_one(OrderAmbivalentPair(10, 2)),
+    ///     bh.hash_one(&OrderAmbivalentPair(2, 10))
+    /// );
+    /// ```
+    #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")]
+    fn hash_one<T: Hash>(&self, x: T) -> u64 {
+        let mut hasher = self.build_hasher();
+        x.hash(&mut hasher);
+        hasher.finish()
+    }
 }
 
 /// Used to create a default [`BuildHasher`] instance for types that implement