]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Generic hashing support. | |
12 | //! | |
13 | //! This module provides a generic way to compute the hash of a value. The | |
14 | //! simplest way to make a type hashable is to use `#[derive(Hash)]`: | |
15 | //! | |
16 | //! # Examples | |
17 | //! | |
18 | //! ```rust | |
c34b1796 | 19 | //! # #![feature(hash)] |
1a4d82fc JJ |
20 | //! use std::hash::{hash, Hash, SipHasher}; |
21 | //! | |
22 | //! #[derive(Hash)] | |
23 | //! struct Person { | |
c34b1796 | 24 | //! id: u32, |
1a4d82fc JJ |
25 | //! name: String, |
26 | //! phone: u64, | |
27 | //! } | |
28 | //! | |
29 | //! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; | |
30 | //! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; | |
31 | //! | |
32 | //! assert!(hash::<_, SipHasher>(&person1) != hash::<_, SipHasher>(&person2)); | |
33 | //! ``` | |
34 | //! | |
35 | //! If you need more control over how a value is hashed, you need to implement | |
36 | //! the trait `Hash`: | |
37 | //! | |
38 | //! ```rust | |
c34b1796 | 39 | //! # #![feature(hash)] |
85aaf69f | 40 | //! use std::hash::{hash, Hash, Hasher, SipHasher}; |
1a4d82fc JJ |
41 | //! |
42 | //! struct Person { | |
c34b1796 | 43 | //! id: u32, |
1a4d82fc JJ |
44 | //! name: String, |
45 | //! phone: u64, | |
46 | //! } | |
47 | //! | |
85aaf69f SL |
48 | //! impl Hash for Person { |
49 | //! fn hash<H: Hasher>(&self, state: &mut H) { | |
1a4d82fc JJ |
50 | //! self.id.hash(state); |
51 | //! self.phone.hash(state); | |
52 | //! } | |
53 | //! } | |
54 | //! | |
55 | //! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; | |
56 | //! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; | |
57 | //! | |
58 | //! assert_eq!(hash::<_, SipHasher>(&person1), hash::<_, SipHasher>(&person2)); | |
59 | //! ``` | |
60 | ||
85aaf69f SL |
61 | #![stable(feature = "rust1", since = "1.0.0")] |
62 | ||
63 | use prelude::*; | |
1a4d82fc | 64 | |
85aaf69f | 65 | use mem; |
1a4d82fc JJ |
66 | |
67 | pub use self::sip::SipHasher; | |
68 | ||
69 | mod sip; | |
70 | ||
71 | /// A hashable type. | |
72 | /// | |
73 | /// The `H` type parameter is an abstract hash state that is used by the `Hash` | |
c34b1796 AL |
74 | /// to compute the hash. |
75 | /// | |
76 | /// If you are also implementing `Eq`, there is an additional property that | |
77 | /// is important: | |
78 | /// | |
79 | /// ```text | |
80 | /// k1 == k2 -> hash(k1) == hash(k2) | |
81 | /// ``` | |
82 | /// | |
83 | /// In other words, if two keys are equal, their hashes should also be equal. | |
84 | /// `HashMap` and `HashSet` both rely on this behavior. | |
85aaf69f SL |
85 | #[stable(feature = "rust1", since = "1.0.0")] |
86 | pub trait Hash { | |
1a4d82fc | 87 | /// Feeds this value into the state given, updating the hasher as necessary. |
85aaf69f SL |
88 | #[stable(feature = "rust1", since = "1.0.0")] |
89 | fn hash<H: Hasher>(&self, state: &mut H); | |
90 | ||
91 | /// Feeds a slice of this type into the state provided. | |
92 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
93 | fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) where Self: Sized { | |
94 | for piece in data { | |
95 | piece.hash(state); | |
96 | } | |
97 | } | |
1a4d82fc JJ |
98 | } |
99 | ||
1a4d82fc | 100 | /// A trait which represents the ability to hash an arbitrary stream of bytes. |
85aaf69f | 101 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 102 | pub trait Hasher { |
85aaf69f | 103 | /// Completes a round of hashing, producing the output hash generated. |
c34b1796 | 104 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
105 | fn finish(&self) -> u64; |
106 | ||
107 | /// Writes some data into this `Hasher` | |
85aaf69f SL |
108 | #[stable(feature = "rust1", since = "1.0.0")] |
109 | fn write(&mut self, bytes: &[u8]); | |
110 | ||
111 | /// Write a single `u8` into this hasher | |
85aaf69f SL |
112 | #[inline] |
113 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
114 | fn write_u8(&mut self, i: u8) { self.write(&[i]) } | |
115 | /// Write a single `u16` into this hasher. | |
85aaf69f SL |
116 | #[inline] |
117 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
118 | fn write_u16(&mut self, i: u16) { | |
119 | self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) }) | |
120 | } | |
121 | /// Write a single `u32` into this hasher. | |
85aaf69f SL |
122 | #[inline] |
123 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
124 | fn write_u32(&mut self, i: u32) { | |
125 | self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) }) | |
126 | } | |
127 | /// Write a single `u64` into this hasher. | |
85aaf69f SL |
128 | #[inline] |
129 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
130 | fn write_u64(&mut self, i: u64) { | |
131 | self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) }) | |
132 | } | |
133 | /// Write a single `usize` into this hasher. | |
85aaf69f SL |
134 | #[inline] |
135 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
136 | fn write_usize(&mut self, i: usize) { | |
137 | if cfg!(target_pointer_width = "32") { | |
138 | self.write_u32(i as u32) | |
139 | } else { | |
140 | self.write_u64(i as u64) | |
141 | } | |
142 | } | |
143 | ||
144 | /// Write a single `i8` into this hasher. | |
85aaf69f SL |
145 | #[inline] |
146 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
147 | fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) } | |
148 | /// Write a single `i16` into this hasher. | |
85aaf69f SL |
149 | #[inline] |
150 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
151 | fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) } | |
152 | /// Write a single `i32` into this hasher. | |
85aaf69f SL |
153 | #[inline] |
154 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
155 | fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) } | |
156 | /// Write a single `i64` into this hasher. | |
85aaf69f SL |
157 | #[inline] |
158 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
159 | fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } | |
160 | /// Write a single `isize` into this hasher. | |
85aaf69f SL |
161 | #[inline] |
162 | #[unstable(feature = "hash", reason = "module was recently redesigned")] | |
163 | fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) } | |
1a4d82fc JJ |
164 | } |
165 | ||
1a4d82fc JJ |
166 | /// Hash a value with the default SipHasher algorithm (two initial keys of 0). |
167 | /// | |
168 | /// The specified value will be hashed with this hasher and then the resulting | |
169 | /// hash will be returned. | |
85aaf69f SL |
170 | #[unstable(feature = "hash", reason = "module was recently redesigned")] |
171 | pub fn hash<T: Hash, H: Hasher + Default>(value: &T) -> u64 { | |
172 | let mut h: H = Default::default(); | |
173 | value.hash(&mut h); | |
174 | h.finish() | |
175 | } | |
176 | ||
1a4d82fc JJ |
177 | ////////////////////////////////////////////////////////////////////////////// |
178 | ||
1a4d82fc JJ |
179 | mod impls { |
180 | use prelude::*; | |
181 | ||
85aaf69f SL |
182 | use slice; |
183 | use super::*; | |
1a4d82fc | 184 | |
85aaf69f SL |
185 | macro_rules! impl_write { |
186 | ($(($ty:ident, $meth:ident),)*) => {$( | |
187 | #[stable(feature = "rust1", since = "1.0.0")] | |
188 | impl Hash for $ty { | |
189 | fn hash<H: Hasher>(&self, state: &mut H) { | |
190 | state.$meth(*self) | |
191 | } | |
192 | ||
193 | fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) { | |
c34b1796 AL |
194 | // FIXME(#23542) Replace with type ascription. |
195 | #![allow(trivial_casts)] | |
9346a6ac | 196 | let newlen = data.len() * ::$ty::BYTES; |
85aaf69f SL |
197 | let ptr = data.as_ptr() as *const u8; |
198 | state.write(unsafe { slice::from_raw_parts(ptr, newlen) }) | |
1a4d82fc JJ |
199 | } |
200 | } | |
85aaf69f | 201 | )*} |
1a4d82fc JJ |
202 | } |
203 | ||
85aaf69f SL |
204 | impl_write! { |
205 | (u8, write_u8), | |
206 | (u16, write_u16), | |
207 | (u32, write_u32), | |
208 | (u64, write_u64), | |
209 | (usize, write_usize), | |
210 | (i8, write_i8), | |
211 | (i16, write_i16), | |
212 | (i32, write_i32), | |
213 | (i64, write_i64), | |
214 | (isize, write_isize), | |
215 | } | |
1a4d82fc | 216 | |
85aaf69f SL |
217 | #[stable(feature = "rust1", since = "1.0.0")] |
218 | impl Hash for bool { | |
219 | fn hash<H: Hasher>(&self, state: &mut H) { | |
220 | state.write_u8(*self as u8) | |
1a4d82fc JJ |
221 | } |
222 | } | |
223 | ||
85aaf69f SL |
224 | #[stable(feature = "rust1", since = "1.0.0")] |
225 | impl Hash for char { | |
226 | fn hash<H: Hasher>(&self, state: &mut H) { | |
227 | state.write_u32(*self as u32) | |
1a4d82fc JJ |
228 | } |
229 | } | |
230 | ||
85aaf69f SL |
231 | #[stable(feature = "rust1", since = "1.0.0")] |
232 | impl Hash for str { | |
233 | fn hash<H: Hasher>(&self, state: &mut H) { | |
1a4d82fc | 234 | state.write(self.as_bytes()); |
85aaf69f | 235 | state.write_u8(0xff) |
1a4d82fc JJ |
236 | } |
237 | } | |
238 | ||
239 | macro_rules! impl_hash_tuple { | |
240 | () => ( | |
85aaf69f SL |
241 | #[stable(feature = "rust1", since = "1.0.0")] |
242 | impl Hash for () { | |
243 | fn hash<H: Hasher>(&self, _state: &mut H) {} | |
1a4d82fc JJ |
244 | } |
245 | ); | |
246 | ||
247 | ( $($name:ident)+) => ( | |
85aaf69f SL |
248 | #[stable(feature = "rust1", since = "1.0.0")] |
249 | impl<$($name: Hash),*> Hash for ($($name,)*) { | |
1a4d82fc | 250 | #[allow(non_snake_case)] |
85aaf69f SL |
251 | fn hash<S: Hasher>(&self, state: &mut S) { |
252 | let ($(ref $name,)*) = *self; | |
253 | $($name.hash(state);)* | |
1a4d82fc JJ |
254 | } |
255 | } | |
256 | ); | |
257 | } | |
258 | ||
259 | impl_hash_tuple! {} | |
260 | impl_hash_tuple! { A } | |
261 | impl_hash_tuple! { A B } | |
262 | impl_hash_tuple! { A B C } | |
263 | impl_hash_tuple! { A B C D } | |
264 | impl_hash_tuple! { A B C D E } | |
265 | impl_hash_tuple! { A B C D E F } | |
266 | impl_hash_tuple! { A B C D E F G } | |
267 | impl_hash_tuple! { A B C D E F G H } | |
268 | impl_hash_tuple! { A B C D E F G H I } | |
269 | impl_hash_tuple! { A B C D E F G H I J } | |
270 | impl_hash_tuple! { A B C D E F G H I J K } | |
271 | impl_hash_tuple! { A B C D E F G H I J K L } | |
272 | ||
85aaf69f SL |
273 | #[stable(feature = "rust1", since = "1.0.0")] |
274 | impl<T: Hash> Hash for [T] { | |
275 | fn hash<H: Hasher>(&self, state: &mut H) { | |
1a4d82fc | 276 | self.len().hash(state); |
85aaf69f | 277 | Hash::hash_slice(self, state) |
1a4d82fc JJ |
278 | } |
279 | } | |
280 | ||
281 | ||
85aaf69f SL |
282 | #[stable(feature = "rust1", since = "1.0.0")] |
283 | impl<'a, T: ?Sized + Hash> Hash for &'a T { | |
284 | fn hash<H: Hasher>(&self, state: &mut H) { | |
1a4d82fc JJ |
285 | (**self).hash(state); |
286 | } | |
287 | } | |
288 | ||
85aaf69f SL |
289 | #[stable(feature = "rust1", since = "1.0.0")] |
290 | impl<'a, T: ?Sized + Hash> Hash for &'a mut T { | |
291 | fn hash<H: Hasher>(&self, state: &mut H) { | |
1a4d82fc JJ |
292 | (**self).hash(state); |
293 | } | |
294 | } | |
295 | ||
85aaf69f SL |
296 | #[stable(feature = "rust1", since = "1.0.0")] |
297 | impl<T> Hash for *const T { | |
298 | fn hash<H: Hasher>(&self, state: &mut H) { | |
299 | state.write_usize(*self as usize) | |
1a4d82fc JJ |
300 | } |
301 | } | |
302 | ||
85aaf69f SL |
303 | #[stable(feature = "rust1", since = "1.0.0")] |
304 | impl<T> Hash for *mut T { | |
305 | fn hash<H: Hasher>(&self, state: &mut H) { | |
306 | state.write_usize(*self as usize) | |
1a4d82fc JJ |
307 | } |
308 | } | |
309 | } |