// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::hash::{Hash, Hasher, BuildHasher}; use std::marker::PhantomData; use std::mem; use sip128::SipHasher128; /// When hashing something that ends up affecting properties like symbol names. We /// want these symbol names to be calculated independent of other factors like /// what architecture you're compiling *from*. /// /// The hashing just uses the standard `Hash` trait, but the implementations of /// `Hash` for the `usize` and `isize` types are *not* architecture independent /// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and /// `isize` completely when hashing. /// /// To do that, we encode all integers to be hashed with some /// arch-independent encoding. /// /// At the moment, we pass i8/u8 straight through and encode /// all other integers using leb128. /// /// This hasher currently always uses the stable Blake2b algorithm /// and allows for variable output lengths through its type /// parameter. pub struct StableHasher { state: SipHasher128, bytes_hashed: u64, width: PhantomData, } impl ::std::fmt::Debug for StableHasher { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "{:?}", self.state) } } pub trait StableHasherResult: Sized { fn finish(hasher: StableHasher) -> Self; } impl StableHasher { pub fn new() -> Self { StableHasher { state: SipHasher128::new_with_keys(0, 0), bytes_hashed: 0, width: PhantomData, } } pub fn finish(self) -> W { W::finish(self) } } impl StableHasherResult for u128 { fn finish(hasher: StableHasher) -> Self { let (_0, _1) = hasher.finalize(); (_0 as u128) | ((_1 as u128) << 64) } } impl StableHasherResult for u64 { fn finish(hasher: StableHasher) -> Self { hasher.finalize().0 } } impl StableHasher { #[inline] pub fn finalize(self) -> (u64, u64) { self.state.finish128() } #[inline] pub fn bytes_hashed(&self) -> u64 { self.bytes_hashed } } // For the non-u8 integer cases we leb128 encode them first. Because small // integers dominate, this significantly and cheaply reduces the number of // bytes hashed, which is good because blake2b is expensive. impl Hasher for StableHasher { fn finish(&self) -> u64 { panic!("use StableHasher::finalize instead"); } #[inline] fn write(&mut self, bytes: &[u8]) { self.state.write(bytes); self.bytes_hashed += bytes.len() as u64; } #[inline] fn write_u8(&mut self, i: u8) { self.state.write_u8(i); self.bytes_hashed += 1; } #[inline] fn write_u16(&mut self, i: u16) { self.state.write_u16(i.to_le()); self.bytes_hashed += 2; } #[inline] fn write_u32(&mut self, i: u32) { self.state.write_u32(i.to_le()); self.bytes_hashed += 4; } #[inline] fn write_u64(&mut self, i: u64) { self.state.write_u64(i.to_le()); self.bytes_hashed += 8; } #[inline] fn write_u128(&mut self, i: u128) { self.state.write_u128(i.to_le()); self.bytes_hashed += 16; } #[inline] fn write_usize(&mut self, i: usize) { self.state.write_usize(i.to_le()); self.bytes_hashed += ::std::mem::size_of::() as u64; } #[inline] fn write_i8(&mut self, i: i8) { self.state.write_i8(i); self.bytes_hashed += 1; } #[inline] fn write_i16(&mut self, i: i16) { self.state.write_i16(i.to_le()); self.bytes_hashed += 2; } #[inline] fn write_i32(&mut self, i: i32) { self.state.write_i32(i.to_le()); self.bytes_hashed += 4; } #[inline] fn write_i64(&mut self, i: i64) { self.state.write_i64(i.to_le()); self.bytes_hashed += 8; } #[inline] fn write_i128(&mut self, i: i128) { self.state.write_i128(i.to_le()); self.bytes_hashed += 16; } #[inline] fn write_isize(&mut self, i: isize) { self.state.write_isize(i.to_le()); self.bytes_hashed += ::std::mem::size_of::() as u64; } } /// Something that can provide a stable hashing context. pub trait StableHashingContextProvider { type ContextType; fn create_stable_hashing_context(&self) -> Self::ContextType; } impl<'a, T: StableHashingContextProvider> StableHashingContextProvider for &'a T { type ContextType = T::ContextType; fn create_stable_hashing_context(&self) -> Self::ContextType { (**self).create_stable_hashing_context() } } impl<'a, T: StableHashingContextProvider> StableHashingContextProvider for &'a mut T { type ContextType = T::ContextType; fn create_stable_hashing_context(&self) -> Self::ContextType { (**self).create_stable_hashing_context() } } /// Something that implements `HashStable` can be hashed in a way that is /// stable across multiple compilation sessions. pub trait HashStable { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher); } /// Implement this for types that can be turned into stable keys like, for /// example, for DefId that can be converted to a DefPathHash. This is used for /// bringing maps into a predictable order before hashing them. pub trait ToStableHashKey { type KeyType: Ord + Clone + Sized + HashStable; fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType; } // Implement HashStable by just calling `Hash::hash()`. This works fine for // self-contained values that don't depend on the hashing context `CTX`. macro_rules! impl_stable_hash_via_hash { ($t:ty) => ( impl HashStable for $t { #[inline] fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { ::std::hash::Hash::hash(self, hasher); } } ); } impl_stable_hash_via_hash!(i8); impl_stable_hash_via_hash!(i16); impl_stable_hash_via_hash!(i32); impl_stable_hash_via_hash!(i64); impl_stable_hash_via_hash!(isize); impl_stable_hash_via_hash!(u8); impl_stable_hash_via_hash!(u16); impl_stable_hash_via_hash!(u32); impl_stable_hash_via_hash!(u64); impl_stable_hash_via_hash!(usize); impl_stable_hash_via_hash!(u128); impl_stable_hash_via_hash!(i128); impl_stable_hash_via_hash!(char); impl_stable_hash_via_hash!(()); impl HashStable for f32 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let val: u32 = unsafe { ::std::mem::transmute(*self) }; val.hash_stable(ctx, hasher); } } impl HashStable for f64 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let val: u64 = unsafe { ::std::mem::transmute(*self) }; val.hash_stable(ctx, hasher); } } impl, CTX> HashStable for (T1,) { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let (ref _0,) = *self; _0.hash_stable(ctx, hasher); } } impl, T2: HashStable, CTX> HashStable for (T1, T2) { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let (ref _0, ref _1) = *self; _0.hash_stable(ctx, hasher); _1.hash_stable(ctx, hasher); } } impl HashStable for (T1, T2, T3) where T1: HashStable, T2: HashStable, T3: HashStable, { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { let (ref _0, ref _1, ref _2) = *self; _0.hash_stable(ctx, hasher); _1.hash_stable(ctx, hasher); _2.hash_stable(ctx, hasher); } } impl, CTX> HashStable for [T] { default fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.len().hash_stable(ctx, hasher); for item in self { item.hash_stable(ctx, hasher); } } } impl, CTX> HashStable for Vec { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (&self[..]).hash_stable(ctx, hasher); } } impl, CTX> HashStable for Box { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(ctx, hasher); } } impl, CTX> HashStable for ::std::rc::Rc { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(ctx, hasher); } } impl, CTX> HashStable for ::std::sync::Arc { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(ctx, hasher); } } impl HashStable for str { #[inline] fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { self.len().hash(hasher); self.as_bytes().hash(hasher); } } impl HashStable for String { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { (&self[..]).hash_stable(hcx, hasher); } } impl ToStableHashKey for String { type KeyType = String; #[inline] fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType { self.clone() } } impl HashStable for bool { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); } } impl HashStable for Option where T: HashStable { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { if let Some(ref value) = *self { 1u8.hash_stable(ctx, hasher); value.hash_stable(ctx, hasher); } else { 0u8.hash_stable(ctx, hasher); } } } impl HashStable for Result where T1: HashStable, T2: HashStable, { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(ctx, hasher); match *self { Ok(ref x) => x.hash_stable(ctx, hasher), Err(ref x) => x.hash_stable(ctx, hasher), } } } impl<'a, T, CTX> HashStable for &'a T where T: HashStable + ?Sized { #[inline] fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { (**self).hash_stable(ctx, hasher); } } impl HashStable for ::std::mem::Discriminant { #[inline] fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { ::std::hash::Hash::hash(self, hasher); } } impl HashStable for ::indexed_vec::IndexVec where T: HashStable, { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.len().hash_stable(ctx, hasher); for v in &self.raw { v.hash_stable(ctx, hasher); } } } impl HashStable for ::indexed_set::IdxSetBuf { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.words().hash_stable(ctx, hasher); } } impl_stable_hash_via_hash!(::std::path::Path); impl_stable_hash_via_hash!(::std::path::PathBuf); impl HashStable for ::std::collections::HashMap where K: ToStableHashKey + Eq + Hash, V: HashStable, R: BuildHasher, { #[inline] fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { hash_stable_hashmap(hcx, hasher, self, ToStableHashKey::to_stable_hash_key); } } impl HashStable for ::std::collections::HashSet where K: ToStableHashKey + Eq + Hash, R: BuildHasher, { fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { let mut keys: Vec<_> = self.iter() .map(|k| k.to_stable_hash_key(hcx)) .collect(); keys.sort_unstable(); keys.hash_stable(hcx, hasher); } } impl HashStable for ::std::collections::BTreeMap where K: ToStableHashKey, V: HashStable, { fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { let mut entries: Vec<_> = self.iter() .map(|(k, v)| (k.to_stable_hash_key(hcx), v)) .collect(); entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2)); entries.hash_stable(hcx, hasher); } } impl HashStable for ::std::collections::BTreeSet where K: ToStableHashKey, { fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { let mut keys: Vec<_> = self.iter() .map(|k| k.to_stable_hash_key(hcx)) .collect(); keys.sort_unstable(); keys.hash_stable(hcx, hasher); } } pub fn hash_stable_hashmap( hcx: &mut HCX, hasher: &mut StableHasher, map: &::std::collections::HashMap, to_stable_hash_key: F) where K: Eq + Hash, V: HashStable, R: BuildHasher, SK: HashStable + Ord + Clone, F: Fn(&K, &HCX) -> SK, W: StableHasherResult, { let mut entries: Vec<_> = map.iter() .map(|(k, v)| (to_stable_hash_key(k, hcx), v)) .collect(); entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2)); entries.hash_stable(hcx, hasher); } /// A vector container that makes sure that its items are hashed in a stable /// order. pub struct StableVec(Vec); impl StableVec { pub fn new(v: Vec) -> Self { StableVec(v) } } impl ::std::ops::Deref for StableVec { type Target = Vec; fn deref(&self) -> &Vec { &self.0 } } impl HashStable for StableVec where T: HashStable + ToStableHashKey { fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { let StableVec(ref v) = *self; let mut sorted: Vec<_> = v.iter() .map(|x| x.to_stable_hash_key(hcx)) .collect(); sorted.sort_unstable(); sorted.hash_stable(hcx, hasher); } }