11//! Stable hasher adapted for cross-platform independent hash.
22
3- use crate :: sip128:: SipHasher128 ;
4-
53use std:: fmt;
64use std:: hash:: Hasher ;
75
86#[ cfg( test) ]
97mod tests;
108
9+ /// Extended [`Hasher`] trait for use with [`StableHasher`].
10+ ///
11+ /// It permits returning an arbitrary type as the [`Self::Hash`] type
12+ /// contrary to the [`Hasher`] trait which can only return `u64`. This
13+ /// is useful when the hasher uses a different representation.
14+ ///
15+ /// # Example
16+ ///
17+ /// ```
18+ /// use std::hash::Hasher;
19+ /// use rustc_stable_hash::ExtendedHasher;
20+ ///
21+ /// struct BogusHasher(u128);
22+ ///
23+ /// impl Hasher for BogusHasher {
24+ /// fn write(&mut self, a: &[u8]) {
25+ /// # self.0 = a.iter().fold(0u128, |acc, a| acc + (*a as u128)) + self.0;
26+ /// // ...
27+ /// }
28+ ///
29+ /// fn finish(&self) -> u64 {
30+ /// self.0 as u64 // really bogus
31+ /// }
32+ /// }
33+ ///
34+ /// impl ExtendedHasher for BogusHasher {
35+ /// type Hash = u128;
36+ ///
37+ /// fn short_write<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
38+ /// self.write(&bytes)
39+ /// }
40+ ///
41+ /// fn finish(self) -> Self::Hash {
42+ /// self.0
43+ /// }
44+ /// }
45+ /// ```
46+ pub trait ExtendedHasher : Hasher {
47+ /// Type returned by the hasher.
48+ type Hash ;
49+
50+ /// Optimized version of [`Hasher::write`] but for small write.
51+ fn short_write < const LEN : usize > ( & mut self , bytes : [ u8 ; LEN ] ) {
52+ self . write ( & bytes) ;
53+ }
54+
55+ /// Finalization method of the hasher to return the [`Hash`].
56+ fn finish ( self ) -> Self :: Hash ;
57+ }
58+
1159/// A Stable Hasher adapted for cross-platform independent hash.
1260///
1361/// When hashing something that ends up affecting properties like symbol names,
@@ -21,24 +69,26 @@ mod tests;
2169/// # Example
2270///
2371/// ```
24- /// use rustc_stable_hash::{StableHasher, StableHasherResult};
72+ /// use rustc_stable_hash::{StableHasher, StableHasherResult, StableSipHasher128 };
2573/// use std::hash::Hasher;
2674///
2775/// struct Hash128([u64; 2]);
2876/// impl StableHasherResult for Hash128 {
77+ /// type Hash = [u64; 2];
78+ ///
2979/// fn finish(hash: [u64; 2]) -> Hash128 {
3080/// Hash128(hash)
3181/// }
3282/// }
3383///
34- /// let mut hasher = StableHasher ::new();
84+ /// let mut hasher = StableSipHasher128 ::new();
3585/// hasher.write_usize(0xFA);
3686///
3787/// let hash: Hash128 = hasher.finish();
3888/// ```
3989#[ must_use]
40- pub struct StableHasher {
41- state : SipHasher128 ,
90+ pub struct StableHasher < H : ExtendedHasher > {
91+ state : H ,
4292}
4393
4494/// Trait for retrieving the result of the stable hashing operation.
@@ -51,6 +101,8 @@ pub struct StableHasher {
51101/// struct Hash128(u128);
52102///
53103/// impl StableHasherResult for Hash128 {
104+ /// type Hash = [u64; 2];
105+ ///
54106/// fn finish(hash: [u64; 2]) -> Hash128 {
55107/// let upper: u128 = hash[0] as u128;
56108/// let lower: u128 = hash[1] as u128;
@@ -60,22 +112,50 @@ pub struct StableHasher {
60112/// }
61113/// ```
62114pub trait StableHasherResult : Sized {
115+ type Hash ;
116+
63117 /// Retrieving the finalized state of the [`StableHasher`] and construct
64118 /// an [`Self`] containing the hash.
65- fn finish ( hasher : [ u64 ; 2 ] ) -> Self ;
119+ fn finish ( hash : Self :: Hash ) -> Self ;
66120}
67121
68- impl StableHasher {
122+ impl < H : ExtendedHasher + Default > StableHasher < H > {
69123 /// Creates a new [`StableHasher`].
70124 ///
71125 /// To be used with the [`Hasher`] implementation and [`StableHasher::finish`].
72126 #[ inline]
73127 #[ must_use]
74128 pub fn new ( ) -> Self {
129+ Default :: default ( )
130+ }
131+ }
132+
133+ impl < H : ExtendedHasher + Default > Default for StableHasher < H > {
134+ /// Creates a new [`StableHasher`].
135+ ///
136+ /// To be used with the [`Hasher`] implementation and [`StableHasher::finish`].
137+ #[ inline]
138+ #[ must_use]
139+ fn default ( ) -> Self {
75140 StableHasher {
76- state : SipHasher128 :: new_with_keys ( 0 , 0 ) ,
141+ state : Default :: default ( ) ,
77142 }
78143 }
144+ }
145+
146+ impl < H : ExtendedHasher > StableHasher < H > {
147+ /// Creates a new [`StableHasher`] from an already created [`ExtendedHasher`].
148+ ///
149+ /// Useful when wanting to initialize a hasher with different parameters/keys.
150+ ///
151+ /// **Important**: Any use of the hasher before being given to a [`StableHasher`]
152+ /// is not covered by this crate guarentees and will make the resulting hash
153+ /// NOT platform independent.
154+ #[ inline]
155+ #[ must_use]
156+ pub fn with_hasher ( state : H ) -> Self {
157+ StableHasher { state }
158+ }
79159
80160 /// Returns the typed-hash value for the values written.
81161 ///
@@ -85,23 +165,23 @@ impl StableHasher {
85165 /// To be used in-place of [`Hasher::finish`].
86166 #[ inline]
87167 #[ must_use]
88- pub fn finish < W : StableHasherResult > ( self ) -> W {
89- W :: finish ( self . state . finish128 ( ) )
168+ pub fn finish < W : StableHasherResult < Hash = H :: Hash > > ( self ) -> W {
169+ W :: finish ( self . state . finish ( ) )
90170 }
91171}
92172
93- impl fmt:: Debug for StableHasher {
173+ impl < H : ExtendedHasher + fmt:: Debug > fmt :: Debug for StableHasher < H > {
94174 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
95175 write ! ( f, "{:?}" , self . state)
96176 }
97177}
98178
99- impl Hasher for StableHasher {
179+ impl < H : ExtendedHasher > Hasher for StableHasher < H > {
100180 /// Returns a combined hash.
101181 ///
102182 /// For greater precision use instead [`StableHasher::finish`].
103183 fn finish ( & self ) -> u64 {
104- self . state . finish ( )
184+ Hasher :: finish ( & self . state )
105185 }
106186
107187 #[ inline]
@@ -192,7 +272,7 @@ impl Hasher for StableHasher {
192272 // Cold path
193273 #[ cold]
194274 #[ inline( never) ]
195- fn hash_value ( state : & mut SipHasher128 , value : u64 ) {
275+ fn hash_value < H : ExtendedHasher > ( state : & mut H , value : u64 ) {
196276 state. write_u8 ( 0xFF ) ;
197277 state. short_write ( value. to_le_bytes ( ) ) ;
198278 }
0 commit comments