forest_hash_utils/
lib.rs

1// Copyright 2020 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4mod key;
5
6pub use self::key::BytesKey;
7use std::hash::Hasher;
8use std::{mem, slice};
9
10/// Custom trait to avoid issues like https://github.com/rust-lang/rust/issues/27108.
11pub trait Hash {
12    fn hash<H: Hasher>(&self, state: &mut H);
13
14    fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
15    where
16        Self: Sized,
17    {
18        for piece in data {
19            piece.hash(state);
20        }
21    }
22}
23
24macro_rules! impl_write {
25    ($(($ty:ident, $meth:ident),)*) => {$(
26        impl Hash for $ty {
27            fn hash<H: Hasher>(&self, state: &mut H) {
28                state.$meth(*self)
29            }
30
31            fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
32                let newlen = data.len() * mem::size_of::<$ty>();
33                let ptr = data.as_ptr() as *const u8;
34                state.write(unsafe { slice::from_raw_parts(ptr, newlen) })
35            }
36        }
37    )*}
38}
39
40impl_write! {
41    (u8, write_u8),
42    (u16, write_u16),
43    (u32, write_u32),
44    (u64, write_u64),
45    (usize, write_usize),
46    (i8, write_i8),
47    (i16, write_i16),
48    (i32, write_i32),
49    (i64, write_i64),
50    (isize, write_isize),
51    (u128, write_u128),
52    (i128, write_i128),
53}
54
55impl Hash for bool {
56    fn hash<H: Hasher>(&self, state: &mut H) {
57        state.write_u8(*self as u8)
58    }
59}
60
61impl Hash for char {
62    fn hash<H: Hasher>(&self, state: &mut H) {
63        state.write_u32(*self as u32)
64    }
65}
66
67impl Hash for str {
68    fn hash<H: Hasher>(&self, state: &mut H) {
69        state.write(self.as_bytes());
70    }
71}
72
73impl Hash for String {
74    fn hash<H: Hasher>(&self, state: &mut H) {
75        state.write(self.as_bytes());
76    }
77}
78
79macro_rules! impl_hash_tuple {
80    () => (
81        impl Hash for () {
82            fn hash<H: Hasher>(&self, _state: &mut H) {}
83        }
84    );
85
86    ( $($name:ident)+) => (
87        impl<$($name: Hash),*> Hash for ($($name,)*) where last_type!($($name,)+): ?Sized {
88            #[allow(non_snake_case)]
89            fn hash<S: Hasher>(&self, state: &mut S) {
90                let ($(ref $name,)*) = *self;
91                $($name.hash(state);)*
92            }
93        }
94    );
95}
96
97macro_rules! last_type {
98    ($a:ident,) => { $a };
99    ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
100}
101
102impl_hash_tuple! {}
103impl_hash_tuple! { A }
104impl_hash_tuple! { A B }
105impl_hash_tuple! { A B C }
106impl_hash_tuple! { A B C D }
107impl_hash_tuple! { A B C D E }
108impl_hash_tuple! { A B C D E F }
109impl_hash_tuple! { A B C D E F G }
110impl_hash_tuple! { A B C D E F G H }
111impl_hash_tuple! { A B C D E F G H I }
112impl_hash_tuple! { A B C D E F G H I J }
113impl_hash_tuple! { A B C D E F G H I J K }
114impl_hash_tuple! { A B C D E F G H I J K L }
115
116impl<T: Hash> Hash for [T] {
117    fn hash<H: Hasher>(&self, state: &mut H) {
118        Hash::hash_slice(self, state)
119    }
120}
121
122impl<T: Hash> Hash for Vec<T> {
123    fn hash<H: Hasher>(&self, state: &mut H) {
124        Hash::hash_slice(self, state)
125    }
126}
127
128impl<T: ?Sized + Hash> Hash for &T {
129    fn hash<H: Hasher>(&self, state: &mut H) {
130        (**self).hash(state);
131    }
132}
133
134impl<T: ?Sized + Hash> Hash for &mut T {
135    fn hash<H: Hasher>(&self, state: &mut H) {
136        (**self).hash(state);
137    }
138}
139
140impl<T: ?Sized> Hash for *const T {
141    fn hash<H: Hasher>(&self, state: &mut H) {
142        if mem::size_of::<Self>() == mem::size_of::<usize>() {
143            // Thin pointer
144            state.write_usize(*self as *const () as usize);
145        } else {
146            // Fat pointer
147            let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
148            state.write_usize(a);
149            state.write_usize(b);
150        }
151    }
152}
153
154impl<T: ?Sized> Hash for *mut T {
155    fn hash<H: Hasher>(&self, state: &mut H) {
156        if mem::size_of::<Self>() == mem::size_of::<usize>() {
157            // Thin pointer
158            state.write_usize(*self as *const () as usize);
159        } else {
160            // Fat pointer
161            let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
162            state.write_usize(a);
163            state.write_usize(b);
164        }
165    }
166}