]>
Commit | Line | Data |
---|---|---|
476ff2be SL |
1 | // Copyright 2016 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 | ||
ea8adc8c | 11 | use std::hash::{Hash, Hasher, BuildHasher}; |
476ff2be SL |
12 | use std::marker::PhantomData; |
13 | use std::mem; | |
abe05a73 | 14 | use sip128::SipHasher128; |
476ff2be | 15 | |
abe05a73 XL |
16 | /// When hashing something that ends up affecting properties like symbol names, |
17 | /// we want these symbol names to be calculated independently of other factors | |
18 | /// like what architecture you're compiling *from*. | |
476ff2be | 19 | /// |
abe05a73 XL |
20 | /// To that end we always convert integers to little-endian format before |
21 | /// hashing and the architecture dependent `isize` and `usize` types are | |
22 | /// extended to 64 bits if needed. | |
476ff2be | 23 | pub struct StableHasher<W> { |
abe05a73 | 24 | state: SipHasher128, |
476ff2be SL |
25 | bytes_hashed: u64, |
26 | width: PhantomData<W>, | |
27 | } | |
28 | ||
cc61c64b XL |
29 | impl<W: StableHasherResult> ::std::fmt::Debug for StableHasher<W> { |
30 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | |
31 | write!(f, "{:?}", self.state) | |
32 | } | |
33 | } | |
34 | ||
476ff2be SL |
35 | pub trait StableHasherResult: Sized { |
36 | fn finish(hasher: StableHasher<Self>) -> Self; | |
37 | } | |
38 | ||
39 | impl<W: StableHasherResult> StableHasher<W> { | |
40 | pub fn new() -> Self { | |
41 | StableHasher { | |
abe05a73 | 42 | state: SipHasher128::new_with_keys(0, 0), |
476ff2be SL |
43 | bytes_hashed: 0, |
44 | width: PhantomData, | |
45 | } | |
46 | } | |
47 | ||
48 | pub fn finish(self) -> W { | |
49 | W::finish(self) | |
50 | } | |
51 | } | |
52 | ||
041b39d2 | 53 | impl StableHasherResult for u128 { |
abe05a73 XL |
54 | fn finish(hasher: StableHasher<Self>) -> Self { |
55 | let (_0, _1) = hasher.finalize(); | |
56 | (_0 as u128) | ((_1 as u128) << 64) | |
041b39d2 XL |
57 | } |
58 | } | |
59 | ||
476ff2be | 60 | impl StableHasherResult for u64 { |
abe05a73 XL |
61 | fn finish(hasher: StableHasher<Self>) -> Self { |
62 | hasher.finalize().0 | |
476ff2be SL |
63 | } |
64 | } | |
65 | ||
66 | impl<W> StableHasher<W> { | |
67 | #[inline] | |
abe05a73 XL |
68 | pub fn finalize(self) -> (u64, u64) { |
69 | self.state.finish128() | |
476ff2be SL |
70 | } |
71 | ||
72 | #[inline] | |
73 | pub fn bytes_hashed(&self) -> u64 { | |
74 | self.bytes_hashed | |
75 | } | |
476ff2be SL |
76 | } |
77 | ||
476ff2be SL |
78 | impl<W> Hasher for StableHasher<W> { |
79 | fn finish(&self) -> u64 { | |
abe05a73 | 80 | panic!("use StableHasher::finalize instead"); |
476ff2be SL |
81 | } |
82 | ||
83 | #[inline] | |
84 | fn write(&mut self, bytes: &[u8]) { | |
85 | self.state.write(bytes); | |
86 | self.bytes_hashed += bytes.len() as u64; | |
87 | } | |
88 | ||
89 | #[inline] | |
90 | fn write_u8(&mut self, i: u8) { | |
91 | self.state.write_u8(i); | |
92 | self.bytes_hashed += 1; | |
93 | } | |
94 | ||
95 | #[inline] | |
96 | fn write_u16(&mut self, i: u16) { | |
abe05a73 XL |
97 | self.state.write_u16(i.to_le()); |
98 | self.bytes_hashed += 2; | |
476ff2be SL |
99 | } |
100 | ||
101 | #[inline] | |
102 | fn write_u32(&mut self, i: u32) { | |
abe05a73 XL |
103 | self.state.write_u32(i.to_le()); |
104 | self.bytes_hashed += 4; | |
476ff2be SL |
105 | } |
106 | ||
107 | #[inline] | |
108 | fn write_u64(&mut self, i: u64) { | |
abe05a73 XL |
109 | self.state.write_u64(i.to_le()); |
110 | self.bytes_hashed += 8; | |
111 | } | |
112 | ||
113 | #[inline] | |
114 | fn write_u128(&mut self, i: u128) { | |
115 | self.state.write_u128(i.to_le()); | |
116 | self.bytes_hashed += 16; | |
476ff2be SL |
117 | } |
118 | ||
119 | #[inline] | |
120 | fn write_usize(&mut self, i: usize) { | |
abe05a73 XL |
121 | // Always treat usize as u64 so we get the same results on 32 and 64 bit |
122 | // platforms. This is important for symbol hashes when cross compiling, | |
123 | // for example. | |
124 | self.state.write_u64((i as u64).to_le()); | |
125 | self.bytes_hashed += 8; | |
476ff2be SL |
126 | } |
127 | ||
128 | #[inline] | |
129 | fn write_i8(&mut self, i: i8) { | |
130 | self.state.write_i8(i); | |
131 | self.bytes_hashed += 1; | |
132 | } | |
133 | ||
134 | #[inline] | |
135 | fn write_i16(&mut self, i: i16) { | |
abe05a73 XL |
136 | self.state.write_i16(i.to_le()); |
137 | self.bytes_hashed += 2; | |
476ff2be SL |
138 | } |
139 | ||
140 | #[inline] | |
141 | fn write_i32(&mut self, i: i32) { | |
abe05a73 XL |
142 | self.state.write_i32(i.to_le()); |
143 | self.bytes_hashed += 4; | |
476ff2be SL |
144 | } |
145 | ||
146 | #[inline] | |
147 | fn write_i64(&mut self, i: i64) { | |
abe05a73 XL |
148 | self.state.write_i64(i.to_le()); |
149 | self.bytes_hashed += 8; | |
150 | } | |
151 | ||
152 | #[inline] | |
153 | fn write_i128(&mut self, i: i128) { | |
154 | self.state.write_i128(i.to_le()); | |
155 | self.bytes_hashed += 16; | |
476ff2be SL |
156 | } |
157 | ||
158 | #[inline] | |
159 | fn write_isize(&mut self, i: isize) { | |
abe05a73 XL |
160 | // Always treat isize as i64 so we get the same results on 32 and 64 bit |
161 | // platforms. This is important for symbol hashes when cross compiling, | |
162 | // for example. | |
163 | self.state.write_i64((i as i64).to_le()); | |
164 | self.bytes_hashed += 8; | |
476ff2be SL |
165 | } |
166 | } | |
cc61c64b | 167 | |
cc61c64b | 168 | /// Something that implements `HashStable<CTX>` can be hashed in a way that is |
3b2f2976 | 169 | /// stable across multiple compilation sessions. |
cc61c64b XL |
170 | pub trait HashStable<CTX> { |
171 | fn hash_stable<W: StableHasherResult>(&self, | |
172 | hcx: &mut CTX, | |
173 | hasher: &mut StableHasher<W>); | |
174 | } | |
175 | ||
ea8adc8c XL |
176 | /// Implement this for types that can be turned into stable keys like, for |
177 | /// example, for DefId that can be converted to a DefPathHash. This is used for | |
178 | /// bringing maps into a predictable order before hashing them. | |
179 | pub trait ToStableHashKey<HCX> { | |
180 | type KeyType: Ord + Clone + Sized + HashStable<HCX>; | |
181 | fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType; | |
182 | } | |
183 | ||
cc61c64b XL |
184 | // Implement HashStable by just calling `Hash::hash()`. This works fine for |
185 | // self-contained values that don't depend on the hashing context `CTX`. | |
186 | macro_rules! impl_stable_hash_via_hash { | |
187 | ($t:ty) => ( | |
188 | impl<CTX> HashStable<CTX> for $t { | |
189 | #[inline] | |
190 | fn hash_stable<W: StableHasherResult>(&self, | |
191 | _: &mut CTX, | |
192 | hasher: &mut StableHasher<W>) { | |
193 | ::std::hash::Hash::hash(self, hasher); | |
194 | } | |
195 | } | |
196 | ); | |
197 | } | |
198 | ||
199 | impl_stable_hash_via_hash!(i8); | |
200 | impl_stable_hash_via_hash!(i16); | |
201 | impl_stable_hash_via_hash!(i32); | |
202 | impl_stable_hash_via_hash!(i64); | |
203 | impl_stable_hash_via_hash!(isize); | |
204 | ||
205 | impl_stable_hash_via_hash!(u8); | |
206 | impl_stable_hash_via_hash!(u16); | |
207 | impl_stable_hash_via_hash!(u32); | |
208 | impl_stable_hash_via_hash!(u64); | |
209 | impl_stable_hash_via_hash!(usize); | |
210 | ||
211 | impl_stable_hash_via_hash!(u128); | |
212 | impl_stable_hash_via_hash!(i128); | |
213 | ||
214 | impl_stable_hash_via_hash!(char); | |
215 | impl_stable_hash_via_hash!(()); | |
216 | ||
217 | impl<CTX> HashStable<CTX> for f32 { | |
218 | fn hash_stable<W: StableHasherResult>(&self, | |
219 | ctx: &mut CTX, | |
220 | hasher: &mut StableHasher<W>) { | |
221 | let val: u32 = unsafe { | |
222 | ::std::mem::transmute(*self) | |
223 | }; | |
224 | val.hash_stable(ctx, hasher); | |
225 | } | |
226 | } | |
227 | ||
228 | impl<CTX> HashStable<CTX> for f64 { | |
229 | fn hash_stable<W: StableHasherResult>(&self, | |
230 | ctx: &mut CTX, | |
231 | hasher: &mut StableHasher<W>) { | |
232 | let val: u64 = unsafe { | |
233 | ::std::mem::transmute(*self) | |
234 | }; | |
235 | val.hash_stable(ctx, hasher); | |
236 | } | |
237 | } | |
238 | ||
0531ce1d XL |
239 | impl<CTX> HashStable<CTX> for ::std::cmp::Ordering { |
240 | fn hash_stable<W: StableHasherResult>(&self, | |
241 | ctx: &mut CTX, | |
242 | hasher: &mut StableHasher<W>) { | |
243 | (*self as i8).hash_stable(ctx, hasher); | |
244 | } | |
245 | } | |
246 | ||
041b39d2 XL |
247 | impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) { |
248 | fn hash_stable<W: StableHasherResult>(&self, | |
249 | ctx: &mut CTX, | |
250 | hasher: &mut StableHasher<W>) { | |
ea8adc8c XL |
251 | let (ref _0,) = *self; |
252 | _0.hash_stable(ctx, hasher); | |
041b39d2 XL |
253 | } |
254 | } | |
255 | ||
cc61c64b XL |
256 | impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2) { |
257 | fn hash_stable<W: StableHasherResult>(&self, | |
258 | ctx: &mut CTX, | |
259 | hasher: &mut StableHasher<W>) { | |
ea8adc8c XL |
260 | let (ref _0, ref _1) = *self; |
261 | _0.hash_stable(ctx, hasher); | |
262 | _1.hash_stable(ctx, hasher); | |
263 | } | |
264 | } | |
265 | ||
266 | impl<T1, T2, T3, CTX> HashStable<CTX> for (T1, T2, T3) | |
267 | where T1: HashStable<CTX>, | |
268 | T2: HashStable<CTX>, | |
269 | T3: HashStable<CTX>, | |
270 | { | |
271 | fn hash_stable<W: StableHasherResult>(&self, | |
272 | ctx: &mut CTX, | |
273 | hasher: &mut StableHasher<W>) { | |
274 | let (ref _0, ref _1, ref _2) = *self; | |
275 | _0.hash_stable(ctx, hasher); | |
276 | _1.hash_stable(ctx, hasher); | |
277 | _2.hash_stable(ctx, hasher); | |
cc61c64b XL |
278 | } |
279 | } | |
280 | ||
281 | impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] { | |
282 | default fn hash_stable<W: StableHasherResult>(&self, | |
283 | ctx: &mut CTX, | |
284 | hasher: &mut StableHasher<W>) { | |
285 | self.len().hash_stable(ctx, hasher); | |
286 | for item in self { | |
287 | item.hash_stable(ctx, hasher); | |
288 | } | |
289 | } | |
290 | } | |
291 | ||
292 | impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> { | |
293 | #[inline] | |
294 | fn hash_stable<W: StableHasherResult>(&self, | |
295 | ctx: &mut CTX, | |
296 | hasher: &mut StableHasher<W>) { | |
297 | (&self[..]).hash_stable(ctx, hasher); | |
298 | } | |
299 | } | |
300 | ||
ea8adc8c | 301 | impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for Box<T> { |
041b39d2 XL |
302 | #[inline] |
303 | fn hash_stable<W: StableHasherResult>(&self, | |
304 | ctx: &mut CTX, | |
305 | hasher: &mut StableHasher<W>) { | |
306 | (**self).hash_stable(ctx, hasher); | |
307 | } | |
308 | } | |
309 | ||
ea8adc8c XL |
310 | impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for ::std::rc::Rc<T> { |
311 | #[inline] | |
312 | fn hash_stable<W: StableHasherResult>(&self, | |
313 | ctx: &mut CTX, | |
314 | hasher: &mut StableHasher<W>) { | |
315 | (**self).hash_stable(ctx, hasher); | |
316 | } | |
317 | } | |
318 | ||
319 | impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for ::std::sync::Arc<T> { | |
041b39d2 XL |
320 | #[inline] |
321 | fn hash_stable<W: StableHasherResult>(&self, | |
322 | ctx: &mut CTX, | |
323 | hasher: &mut StableHasher<W>) { | |
324 | (**self).hash_stable(ctx, hasher); | |
325 | } | |
326 | } | |
327 | ||
cc61c64b XL |
328 | impl<CTX> HashStable<CTX> for str { |
329 | #[inline] | |
330 | fn hash_stable<W: StableHasherResult>(&self, | |
331 | _: &mut CTX, | |
332 | hasher: &mut StableHasher<W>) { | |
333 | self.len().hash(hasher); | |
334 | self.as_bytes().hash(hasher); | |
335 | } | |
336 | } | |
337 | ||
7cac9316 XL |
338 | |
339 | impl<CTX> HashStable<CTX> for String { | |
340 | #[inline] | |
341 | fn hash_stable<W: StableHasherResult>(&self, | |
342 | hcx: &mut CTX, | |
343 | hasher: &mut StableHasher<W>) { | |
344 | (&self[..]).hash_stable(hcx, hasher); | |
345 | } | |
346 | } | |
347 | ||
ea8adc8c XL |
348 | impl<HCX> ToStableHashKey<HCX> for String { |
349 | type KeyType = String; | |
350 | #[inline] | |
351 | fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType { | |
352 | self.clone() | |
353 | } | |
354 | } | |
355 | ||
cc61c64b XL |
356 | impl<CTX> HashStable<CTX> for bool { |
357 | #[inline] | |
358 | fn hash_stable<W: StableHasherResult>(&self, | |
359 | ctx: &mut CTX, | |
360 | hasher: &mut StableHasher<W>) { | |
361 | (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); | |
362 | } | |
363 | } | |
364 | ||
365 | ||
366 | impl<T, CTX> HashStable<CTX> for Option<T> | |
367 | where T: HashStable<CTX> | |
368 | { | |
369 | #[inline] | |
370 | fn hash_stable<W: StableHasherResult>(&self, | |
371 | ctx: &mut CTX, | |
372 | hasher: &mut StableHasher<W>) { | |
373 | if let Some(ref value) = *self { | |
374 | 1u8.hash_stable(ctx, hasher); | |
375 | value.hash_stable(ctx, hasher); | |
376 | } else { | |
377 | 0u8.hash_stable(ctx, hasher); | |
378 | } | |
379 | } | |
380 | } | |
381 | ||
ea8adc8c XL |
382 | impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2> |
383 | where T1: HashStable<CTX>, | |
384 | T2: HashStable<CTX>, | |
385 | { | |
386 | #[inline] | |
387 | fn hash_stable<W: StableHasherResult>(&self, | |
388 | ctx: &mut CTX, | |
389 | hasher: &mut StableHasher<W>) { | |
390 | mem::discriminant(self).hash_stable(ctx, hasher); | |
391 | match *self { | |
392 | Ok(ref x) => x.hash_stable(ctx, hasher), | |
393 | Err(ref x) => x.hash_stable(ctx, hasher), | |
394 | } | |
395 | } | |
396 | } | |
397 | ||
cc61c64b | 398 | impl<'a, T, CTX> HashStable<CTX> for &'a T |
ea8adc8c | 399 | where T: HashStable<CTX> + ?Sized |
cc61c64b XL |
400 | { |
401 | #[inline] | |
402 | fn hash_stable<W: StableHasherResult>(&self, | |
403 | ctx: &mut CTX, | |
404 | hasher: &mut StableHasher<W>) { | |
405 | (**self).hash_stable(ctx, hasher); | |
406 | } | |
407 | } | |
408 | ||
409 | impl<T, CTX> HashStable<CTX> for ::std::mem::Discriminant<T> { | |
410 | #[inline] | |
411 | fn hash_stable<W: StableHasherResult>(&self, | |
412 | _: &mut CTX, | |
413 | hasher: &mut StableHasher<W>) { | |
414 | ::std::hash::Hash::hash(self, hasher); | |
415 | } | |
416 | } | |
417 | ||
ea8adc8c XL |
418 | impl<I: ::indexed_vec::Idx, T, CTX> HashStable<CTX> for ::indexed_vec::IndexVec<I, T> |
419 | where T: HashStable<CTX>, | |
cc61c64b XL |
420 | { |
421 | fn hash_stable<W: StableHasherResult>(&self, | |
422 | ctx: &mut CTX, | |
423 | hasher: &mut StableHasher<W>) { | |
424 | self.len().hash_stable(ctx, hasher); | |
ea8adc8c | 425 | for v in &self.raw { |
cc61c64b XL |
426 | v.hash_stable(ctx, hasher); |
427 | } | |
428 | } | |
429 | } | |
430 | ||
ea8adc8c XL |
431 | |
432 | impl<I: ::indexed_vec::Idx, CTX> HashStable<CTX> for ::indexed_set::IdxSetBuf<I> | |
cc61c64b XL |
433 | { |
434 | fn hash_stable<W: StableHasherResult>(&self, | |
435 | ctx: &mut CTX, | |
436 | hasher: &mut StableHasher<W>) { | |
ea8adc8c | 437 | self.words().hash_stable(ctx, hasher); |
cc61c64b XL |
438 | } |
439 | } | |
440 | ||
ea8adc8c XL |
441 | impl_stable_hash_via_hash!(::std::path::Path); |
442 | impl_stable_hash_via_hash!(::std::path::PathBuf); | |
443 | ||
444 | impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R> | |
445 | where K: ToStableHashKey<HCX> + Eq + Hash, | |
446 | V: HashStable<HCX>, | |
447 | R: BuildHasher, | |
cc61c64b | 448 | { |
ea8adc8c | 449 | #[inline] |
cc61c64b | 450 | fn hash_stable<W: StableHasherResult>(&self, |
ea8adc8c | 451 | hcx: &mut HCX, |
cc61c64b | 452 | hasher: &mut StableHasher<W>) { |
ea8adc8c XL |
453 | hash_stable_hashmap(hcx, hasher, self, ToStableHashKey::to_stable_hash_key); |
454 | } | |
455 | } | |
456 | ||
457 | impl<K, R, HCX> HashStable<HCX> for ::std::collections::HashSet<K, R> | |
458 | where K: ToStableHashKey<HCX> + Eq + Hash, | |
459 | R: BuildHasher, | |
460 | { | |
461 | fn hash_stable<W: StableHasherResult>(&self, | |
462 | hcx: &mut HCX, | |
463 | hasher: &mut StableHasher<W>) { | |
464 | let mut keys: Vec<_> = self.iter() | |
465 | .map(|k| k.to_stable_hash_key(hcx)) | |
466 | .collect(); | |
467 | keys.sort_unstable(); | |
468 | keys.hash_stable(hcx, hasher); | |
469 | } | |
470 | } | |
471 | ||
472 | impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V> | |
473 | where K: ToStableHashKey<HCX>, | |
474 | V: HashStable<HCX>, | |
475 | { | |
476 | fn hash_stable<W: StableHasherResult>(&self, | |
477 | hcx: &mut HCX, | |
478 | hasher: &mut StableHasher<W>) { | |
479 | let mut entries: Vec<_> = self.iter() | |
480 | .map(|(k, v)| (k.to_stable_hash_key(hcx), v)) | |
481 | .collect(); | |
482 | entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2)); | |
483 | entries.hash_stable(hcx, hasher); | |
484 | } | |
485 | } | |
486 | ||
487 | impl<K, HCX> HashStable<HCX> for ::std::collections::BTreeSet<K> | |
488 | where K: ToStableHashKey<HCX>, | |
489 | { | |
490 | fn hash_stable<W: StableHasherResult>(&self, | |
491 | hcx: &mut HCX, | |
492 | hasher: &mut StableHasher<W>) { | |
493 | let mut keys: Vec<_> = self.iter() | |
494 | .map(|k| k.to_stable_hash_key(hcx)) | |
495 | .collect(); | |
496 | keys.sort_unstable(); | |
497 | keys.hash_stable(hcx, hasher); | |
498 | } | |
499 | } | |
500 | ||
501 | pub fn hash_stable_hashmap<HCX, K, V, R, SK, F, W>( | |
502 | hcx: &mut HCX, | |
503 | hasher: &mut StableHasher<W>, | |
504 | map: &::std::collections::HashMap<K, V, R>, | |
505 | to_stable_hash_key: F) | |
506 | where K: Eq + Hash, | |
507 | V: HashStable<HCX>, | |
508 | R: BuildHasher, | |
509 | SK: HashStable<HCX> + Ord + Clone, | |
510 | F: Fn(&K, &HCX) -> SK, | |
511 | W: StableHasherResult, | |
512 | { | |
513 | let mut entries: Vec<_> = map.iter() | |
514 | .map(|(k, v)| (to_stable_hash_key(k, hcx), v)) | |
515 | .collect(); | |
516 | entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2)); | |
517 | entries.hash_stable(hcx, hasher); | |
518 | } | |
519 | ||
520 | ||
521 | /// A vector container that makes sure that its items are hashed in a stable | |
522 | /// order. | |
523 | pub struct StableVec<T>(Vec<T>); | |
524 | ||
525 | impl<T> StableVec<T> { | |
526 | pub fn new(v: Vec<T>) -> Self { | |
527 | StableVec(v) | |
528 | } | |
529 | } | |
530 | ||
531 | impl<T> ::std::ops::Deref for StableVec<T> { | |
532 | type Target = Vec<T>; | |
533 | ||
534 | fn deref(&self) -> &Vec<T> { | |
535 | &self.0 | |
536 | } | |
537 | } | |
538 | ||
539 | impl<T, HCX> HashStable<HCX> for StableVec<T> | |
540 | where T: HashStable<HCX> + ToStableHashKey<HCX> | |
541 | { | |
542 | fn hash_stable<W: StableHasherResult>(&self, | |
543 | hcx: &mut HCX, | |
544 | hasher: &mut StableHasher<W>) { | |
545 | let StableVec(ref v) = *self; | |
546 | ||
547 | let mut sorted: Vec<_> = v.iter() | |
548 | .map(|x| x.to_stable_hash_key(hcx)) | |
549 | .collect(); | |
550 | sorted.sort_unstable(); | |
551 | sorted.hash_stable(hcx, hasher); | |
cc61c64b XL |
552 | } |
553 | } |