turbo_tasks_hash/
deterministic_hash.rs

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