extern crate alloc; use crate::hash::Hashable; use alloc::string::String; use alloc::vec::Vec; use core::hash::Hasher; use core::mem; use core::slice; macro_rules! impl_write { ($(($ty:ident, $meth:ident),)*) => {$( impl Hashable for $ty { fn hash(&self, state: &mut H) { state.$meth(*self) } #[allow(trivial_casts, unsafe_code)] fn hash_slice(data: &[$ty], state: &mut H) { let newlen = data.len() * mem::size_of::<$ty>(); let ptr = data.as_ptr() as *const u8; state.write(unsafe { slice::from_raw_parts(ptr, newlen) }) } } )*} } impl_write! { (u8, write_u8), (u16, write_u16), (u32, write_u32), (u64, write_u64), (usize, write_usize), (i8, write_i8), (i16, write_i16), (i32, write_i32), (i64, write_i64), (isize, write_isize), // unstable: (u128, write_u128), // unstable: (i128, write_i128), } macro_rules! impl_array { ($ty:ident $($N:expr)+) => {$( impl Hashable for [$ty; $N] { fn hash(&self, state: &mut H) { state.write(self.as_ref()) } #[allow(trivial_casts, unsafe_code)] fn hash_slice(data: &[[$ty; $N]], state: &mut H) { let newlen = data.len() * mem::size_of::<[$ty; $N]>(); let ptr = data.as_ptr() as *const u8; state.write(unsafe { slice::from_raw_parts(ptr, newlen) }) } } )*} } impl_array! { u8 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 } impl Hashable for Vec { fn hash(&self, state: &mut H) { state.write(self.as_ref()); } } impl Hashable for bool { fn hash(&self, state: &mut H) { state.write_u8(*self as u8) } } impl Hashable for char { fn hash(&self, state: &mut H) { state.write_u32(*self as u32) } } impl Hashable for str { fn hash(&self, state: &mut H) { state.write(self.as_bytes()); // empty str nope: state.write_u8(0xff) } } impl Hashable for String { fn hash(&self, state: &mut H) { state.write(self.as_bytes()); // empty str nope: state.write_u8(0xff) } } macro_rules! impl_hash_tuple { () => ( impl Hashable for () { fn hash(&self, _: &mut H) {} } ); ( $($name:ident)+) => ( impl),*> Hashable for ($($name,)*) where last_type!($($name,)+): ?Sized { #[allow(non_snake_case)] fn hash(&self, state: &mut Z) { let ($(ref $name,)*) = *self; $($name.hash(state);)* } } ); } macro_rules! last_type { ($a:ident,) => { $a }; ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; } impl_hash_tuple! {} impl_hash_tuple! { A } impl_hash_tuple! { A B } impl_hash_tuple! { A B C } impl_hash_tuple! { A B C D } impl_hash_tuple! { A B C D E } impl_hash_tuple! { A B C D E F } impl_hash_tuple! { A B C D E F G } impl_hash_tuple! { A B C D E F G H } impl_hash_tuple! { A B C D E F G H I } impl_hash_tuple! { A B C D E F G H I J } impl_hash_tuple! { A B C D E F G H I J K } impl_hash_tuple! { A B C D E F G H I J K L } impl> Hashable for [T] { fn hash(&self, state: &mut H) { self.len().hash(state); Hashable::hash_slice(self, state) } } impl<'a, H: Hasher, T: ?Sized + Hashable> Hashable for &'a T { fn hash(&self, state: &mut H) { (**self).hash(state); } } impl<'a, H: Hasher, T: ?Sized + Hashable> Hashable for &'a mut T { fn hash(&self, state: &mut H) { (**self).hash(state); } } impl Hashable for *const T { #[allow(trivial_casts, unsafe_code)] fn hash(&self, state: &mut H) { if mem::size_of::() == mem::size_of::() { // Thin pointer state.write_usize(*self as *const () as usize); } else { // Fat pointer let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) }; state.write_usize(a); state.write_usize(b); } } } impl Hashable for *mut T { #[allow(trivial_casts, unsafe_code)] fn hash(&self, state: &mut H) { if mem::size_of::() == mem::size_of::() { // Thin pointer state.write_usize(*self as *const () as usize); } else { // Fat pointer let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) }; state.write_usize(a); state.write_usize(b); } } }