Skip to main content

turbo_tasks_hash/
deterministic_hash.rs

1use std::mem::Discriminant;
2
3use smallvec::SmallVec;
4pub use turbo_tasks_macros::DeterministicHash;
5
6macro_rules! deterministic_hash_number {
7    ($(($ty:ident, $meth:ident),)*) => {$(
8        impl DeterministicHash for $ty {
9            fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
10                state.$meth(*self);
11            }
12        }
13    )*}
14}
15
16macro_rules! impl_write_number {
17    ($(($ty:ident, $meth:ident),)*) => {$(
18        /// Writes a single `$ty` to this hasher
19        #[inline]
20        fn $meth(&mut self, i: $ty) {
21            // Apple silicon and Intel chips both use little endian, so this should be fast.
22            let little_endian = i.to_le_bytes();
23            self.write_bytes(&little_endian);
24        }
25    )*}
26}
27
28/// Signals the implementor can safely be hashed in a replicatable way across platforms and process
29/// runs.
30///
31/// Note that the default [`std::hash::Hash`] trait used by Rust allows for hashing that differs
32/// across process runs, so it is not suitable for filesystem cache with turbo-tasks.
33///
34/// It's very important that `Vc`s never implement this, since they are not consistent from run to
35/// run. The value that they wrap, however, can implement the trait.
36pub trait DeterministicHash {
37    /// Adds `self`'s bytes to the [`DeterministicHasher`]'s state, in a way that is replicatable on
38    /// any platform or process run.
39    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H);
40}
41
42/// Signals the implementor can safely hash in a replicatable way across platforms and process runs.
43///
44/// Note that the default [`std::hash::Hash`] trait used by Rust allows for hashing that differs
45/// across process runs, so it is not suitable for filesystem cache with turbo-tasks.
46pub trait DeterministicHasher {
47    fn finish(&self) -> u64;
48    fn write_bytes(&mut self, bytes: &[u8]);
49
50    /// Writes a single `u8` to this hasher
51    #[inline]
52    fn write_u8(&mut self, i: u8) {
53        self.write_bytes(&[i]);
54    }
55
56    /// Writes a single `usize` to this hasher
57    #[inline]
58    fn write_usize(&mut self, i: usize) {
59        // usize can be 4 or 8 bytes, standardize on the larger.
60        // As long as the original value is smaller than 4 bytes, the two will hash
61        // equivalently.
62        self.write_u64(i as u64);
63    }
64
65    /// Writes a single `isize` to this hasher
66    #[inline]
67    fn write_isize(&mut self, i: isize) {
68        // isize can be 4 or 8 bytes, standardize on the larger.
69        // As long as the original value is smaller than 4 bytes, the two will hash
70        // equivalently.
71        self.write_i64(i as i64);
72    }
73
74    impl_write_number! {
75        (u16, write_u16),
76        (u32, write_u32),
77        (u64, write_u64),
78        (i8, write_i8),
79        (i16, write_i16),
80        (i32, write_i32),
81        (i64, write_i64),
82        (u128, write_u128),
83        (i128, write_i128),
84    }
85}
86
87deterministic_hash_number! {
88    (u8, write_u8),
89    (u16, write_u16),
90    (u32, write_u32),
91    (u64, write_u64),
92    (usize, write_usize),
93    (i8, write_i8),
94    (i16, write_i16),
95    (i32, write_i32),
96    (i64, write_i64),
97    (isize, write_isize),
98    (u128, write_u128),
99    (i128, write_i128),
100}
101
102impl<T: ?Sized + DeterministicHash> DeterministicHash for &T {
103    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
104        (**self).deterministic_hash(state);
105    }
106}
107
108impl DeterministicHash for [u8] {
109    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
110        state.write_usize(self.len());
111        state.write_bytes(self);
112    }
113}
114
115impl DeterministicHash for String {
116    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
117        state.write_usize(self.len());
118        state.write_bytes(self.as_bytes());
119    }
120}
121
122impl DeterministicHash for &str {
123    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
124        state.write_usize(self.len());
125        state.write_bytes(self.as_bytes());
126    }
127}
128
129impl DeterministicHash for bool {
130    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
131        state.write_u8(*self as u8);
132    }
133}
134
135impl<T: DeterministicHash> DeterministicHash for Option<T> {
136    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
137        match self {
138            None => state.write_u8(0),
139            Some(v) => {
140                state.write_u8(1);
141                v.deterministic_hash(state);
142            }
143        }
144    }
145}
146
147impl<T: DeterministicHash> DeterministicHash for Vec<T> {
148    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
149        state.write_usize(self.len());
150        for v in self {
151            v.deterministic_hash(state);
152        }
153    }
154}
155
156impl<T: DeterministicHash, const N: usize> DeterministicHash for SmallVec<[T; N]> {
157    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
158        state.write_usize(self.len());
159        for v in self {
160            v.deterministic_hash(state);
161        }
162    }
163}
164
165impl DeterministicHash for () {
166    fn deterministic_hash<H: DeterministicHasher>(&self, _state: &mut H) {}
167}
168
169macro_rules! tuple_impls {
170    ( $( $name:ident )+ ) => {
171        impl<$($name: DeterministicHash),+> DeterministicHash for ($($name,)+)
172        {
173            #[allow(non_snake_case)]
174            fn deterministic_hash<Hasher: DeterministicHasher>(&self, state: &mut Hasher) {
175                let ($(ref $name,)+) = *self;
176                $($name.deterministic_hash(state);)+
177            }
178        }
179    };
180}
181
182// Implement `DeterministicHash` for all tuples of 1 to 12 elements.
183tuple_impls! { A }
184tuple_impls! { A B }
185tuple_impls! { A B C }
186tuple_impls! { A B C D }
187tuple_impls! { A B C D E }
188tuple_impls! { A B C D E F }
189tuple_impls! { A B C D E F G }
190tuple_impls! { A B C D E F G H }
191tuple_impls! { A B C D E F G H I }
192tuple_impls! { A B C D E F G H I J }
193tuple_impls! { A B C D E F G H I J K }
194tuple_impls! { A B C D E F G H I J K L }
195
196/// HasherWrapper allows the DeterministicHasher to be used as a Hasher, for
197/// standard types that do not allow us to directly access their internals.
198struct HasherWrapper<'a, D: DeterministicHasher>(&'a mut D);
199impl<D: DeterministicHasher> std::hash::Hasher for HasherWrapper<'_, D> {
200    fn write(&mut self, bytes: &[u8]) {
201        self.0.write_bytes(bytes);
202    }
203
204    fn finish(&self) -> u64 {
205        unimplemented!();
206    }
207}
208
209impl<T> DeterministicHash for Discriminant<T> {
210    fn deterministic_hash<H: DeterministicHasher>(&self, state: &mut H) {
211        // The Discriminant does not allow us to access its internal state, but does
212        // allow us to Hash it.
213        let mut wrapper = HasherWrapper(state);
214        std::hash::Hash::hash(self, &mut wrapper);
215    }
216}