1
1
//! Stable hasher adapted for cross-platform independent hash.
2
2
3
- use crate :: sip128:: SipHasher128 ;
4
-
5
3
use std:: fmt;
6
4
use std:: hash:: Hasher ;
7
5
8
6
#[ cfg( test) ]
9
7
mod tests;
10
8
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 DumbHasher(u128);
22
+ ///
23
+ /// impl Hasher for DumbHasher {
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 dumb
31
+ /// }
32
+ /// }
33
+ ///
34
+ /// impl ExtendedHasher for DumbHasher {
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
+
11
59
/// A Stable Hasher adapted for cross-platform independent hash.
12
60
///
13
61
/// When hashing something that ends up affecting properties like symbol names,
@@ -21,24 +69,26 @@ mod tests;
21
69
/// # Example
22
70
///
23
71
/// ```
24
- /// use rustc_stable_hash::{StableHasher, StableHasherResult};
72
+ /// use rustc_stable_hash::{StableHasher, StableHasherResult, StableSipHasher128 };
25
73
/// use std::hash::Hasher;
26
74
///
27
75
/// struct Hash128([u64; 2]);
28
76
/// impl StableHasherResult for Hash128 {
77
+ /// type Hash = [u64; 2];
78
+ ///
29
79
/// fn finish(hash: [u64; 2]) -> Hash128 {
30
80
/// Hash128(hash)
31
81
/// }
32
82
/// }
33
83
///
34
- /// let mut hasher = StableHasher ::new();
84
+ /// let mut hasher = StableSipHasher128 ::new();
35
85
/// hasher.write_usize(0xFA);
36
86
///
37
87
/// let hash: Hash128 = hasher.finish();
38
88
/// ```
39
89
#[ must_use]
40
- pub struct StableHasher {
41
- state : SipHasher128 ,
90
+ pub struct StableHasher < H : ExtendedHasher > {
91
+ state : H ,
42
92
}
43
93
44
94
/// Trait for retrieving the result of the stable hashing operation.
@@ -51,6 +101,8 @@ pub struct StableHasher {
51
101
/// struct Hash128(u128);
52
102
///
53
103
/// impl StableHasherResult for Hash128 {
104
+ /// type Hash = [u64; 2];
105
+ ///
54
106
/// fn finish(hash: [u64; 2]) -> Hash128 {
55
107
/// let upper: u128 = hash[0] as u128;
56
108
/// let lower: u128 = hash[1] as u128;
@@ -60,22 +112,50 @@ pub struct StableHasher {
60
112
/// }
61
113
/// ```
62
114
pub trait StableHasherResult : Sized {
115
+ type Hash ;
116
+
63
117
/// Retrieving the finalized state of the [`StableHasher`] and construct
64
118
/// an [`Self`] containing the hash.
65
- fn finish ( hasher : [ u64 ; 2 ] ) -> Self ;
119
+ fn finish ( hash : Self :: Hash ) -> Self ;
66
120
}
67
121
68
- impl StableHasher {
122
+ impl < H : ExtendedHasher + Default > StableHasher < H > {
69
123
/// Creates a new [`StableHasher`].
70
124
///
71
125
/// To be used with the [`Hasher`] implementation and [`StableHasher::finish`].
72
126
#[ inline]
73
127
#[ must_use]
74
128
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 {
75
140
StableHasher {
76
- state : SipHasher128 :: new_with_keys ( 0 , 0 ) ,
141
+ state : Default :: default ( ) ,
77
142
}
78
143
}
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 guarentes and will make the resulting hash
153
+ /// NOT cross-platform independent.
154
+ #[ inline]
155
+ #[ must_use]
156
+ pub fn with_hasher ( state : H ) -> Self {
157
+ StableHasher { state }
158
+ }
79
159
80
160
/// Returns the typed-hash value for the values written.
81
161
///
@@ -85,23 +165,23 @@ impl StableHasher {
85
165
/// To be used in-place of [`Hasher::finish`].
86
166
#[ inline]
87
167
#[ 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 ( ) )
90
170
}
91
171
}
92
172
93
- impl fmt:: Debug for StableHasher {
173
+ impl < H : ExtendedHasher + fmt:: Debug > fmt :: Debug for StableHasher < H > {
94
174
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
95
175
write ! ( f, "{:?}" , self . state)
96
176
}
97
177
}
98
178
99
- impl Hasher for StableHasher {
179
+ impl < H : ExtendedHasher > Hasher for StableHasher < H > {
100
180
/// Returns a combined hash.
101
181
///
102
182
/// For greater precision use instead [`StableHasher::finish`].
103
183
fn finish ( & self ) -> u64 {
104
- self . state . finish ( )
184
+ Hasher :: finish ( & self . state )
105
185
}
106
186
107
187
#[ inline]
@@ -192,7 +272,7 @@ impl Hasher for StableHasher {
192
272
// Cold path
193
273
#[ cold]
194
274
#[ inline( never) ]
195
- fn hash_value ( state : & mut SipHasher128 , value : u64 ) {
275
+ fn hash_value < H : ExtendedHasher > ( state : & mut H , value : u64 ) {
196
276
state. write_u8 ( 0xFF ) ;
197
277
state. short_write ( value. to_le_bytes ( ) ) ;
198
278
}
0 commit comments