Skip to main content

cubecl_ir/
type_hash.rs

1use alloc::borrow::ToOwned;
2use core::hash::Hasher;
3use enumset::EnumSetType;
4
5/// A hash of a type's structure
6pub trait TypeHash {
7    /// Generate a stable hash of the type structure.
8    ///
9    /// This recursively hashes the names and types of each variant and field, and uses an unseeded
10    /// hasher to ensure the hash is stable across compilations and executions. The hash should only
11    /// change if a field/variant is renamed, added, or its type is changed.
12    #[allow(unused)]
13    fn type_hash() -> u64 {
14        let mut hasher = fnv::FnvHasher::default();
15        Self::write_hash(&mut hasher);
16        hasher.finish()
17    }
18
19    /// Write the structure of the type to the hasher
20    fn write_hash(hasher: &mut impl Hasher);
21}
22
23macro_rules! impl_type_hash {
24    ($( $($ty: ident)::* $(<$($l: lifetime,)* $($T: ident $(: $(? $Sized: ident)? $($(+)? $B: ident)*)?),+>)?,)*) => {
25        $(
26            impl $(<$($l,)* $($T: $crate::TypeHash $($(+ ?$Sized)? $(+ $B)*)? ),*>)? TypeHash for $($ty)::* $(<$($l,)* $($T),+>)? {
27                fn write_hash(hasher: &mut impl core::hash::Hasher) {
28                    hasher.write(stringify!($($ty)::*).as_bytes());
29                    $($(
30                        $T::write_hash(hasher);
31                    )+)?
32                }
33            }
34        )*
35    };
36}
37
38impl_type_hash!(
39    bool,
40    u8,
41    i8,
42    u16,
43    i16,
44    u32,
45    i32,
46    u64,
47    i64,
48    u128,
49    i128,
50    usize,
51    isize,
52    f32,
53    f64,
54    str,
55    core::any::TypeId,
56    alloc::borrow::Cow<'a, T: ?Sized + ToOwned>,
57    alloc::boxed::Box<T: ?Sized>,
58    core::cell::Cell<T: ?Sized>,
59    core::cell::Ref<'a, T: ?Sized>,
60    core::cell::RefCell<T: ?Sized>,
61    core::cell::RefMut<'a, T>,
62    core::cell::UnsafeCell<T>,
63    core::cmp::Ordering,
64    core::cmp::Reverse<T>,
65    alloc::collections::BinaryHeap<T>,
66    alloc::collections::BTreeMap<K, V>,
67    alloc::collections::BTreeSet<T>,
68    alloc::collections::LinkedList<T>,
69    alloc::collections::VecDeque<T>,
70    core::hash::BuildHasherDefault<T>,
71    core::marker::PhantomData<T: ?Sized>,
72    core::mem::ManuallyDrop<T: ?Sized>,
73    core::mem::MaybeUninit<T>,
74    core::net::IpAddr,
75    core::net::Ipv4Addr,
76    core::net::Ipv6Addr,
77    core::net::SocketAddr,
78    core::net::SocketAddrV4,
79    core::net::SocketAddrV6,
80    core::num::FpCategory,
81    core::num::NonZeroI128,
82    core::num::NonZeroI16,
83    core::num::NonZeroI32,
84    core::num::NonZeroI64,
85    core::num::NonZeroI8,
86    core::num::NonZeroIsize,
87    core::num::NonZeroU128,
88    core::num::NonZeroU16,
89    core::num::NonZeroU32,
90    core::num::NonZeroU64,
91    core::num::NonZeroU8,
92    core::num::NonZeroUsize,
93    core::num::Wrapping<T>,
94    core::ops::Bound<T>,
95    core::ops::Range<T>,
96    core::ops::RangeFrom<T>,
97    core::ops::RangeInclusive<T>,
98    core::ops::RangeFull,
99    core::ops::RangeTo<T>,
100    core::ops::RangeToInclusive<T>,
101    core::option::Option<T>,
102    core::pin::Pin<T>,
103    core::primitive::char,
104    core::ptr::NonNull<T: ?Sized>,
105    alloc::rc::Rc<T: ?Sized>,
106    alloc::rc::Weak<T: ?Sized>,
107    core::result::Result<T, E>,
108    alloc::string::String,
109    core::time::Duration,
110    alloc::vec::Vec<T>,
111    hashbrown::HashMap<K, V>,
112    hashbrown::HashSet<T>,
113    portable_atomic::AtomicBool,
114    portable_atomic::AtomicI16,
115    portable_atomic::AtomicI32,
116    portable_atomic::AtomicI64,
117    portable_atomic::AtomicI8,
118    portable_atomic::AtomicIsize,
119    portable_atomic::AtomicPtr<T>,
120    portable_atomic::AtomicU16,
121    portable_atomic::AtomicU32,
122    portable_atomic::AtomicU64,
123    portable_atomic::AtomicU8,
124    portable_atomic::AtomicUsize,
125    enumset::EnumSet<T: EnumSetType>,
126    internment::Intern<T: ?Sized>,
127    bumpalo::Bump,
128);
129
130macro_rules! impl_type_hash_tuple {
131    ($($T: ident),*) => {
132        impl <$($T: $crate::TypeHash),*> TypeHash for ($($T,)*) {
133            fn write_hash(hasher: &mut impl core::hash::Hasher) {
134                hasher.write(b"()");
135                $(
136                    $T::write_hash(hasher);
137                )*
138            }
139        }
140    };
141}
142
143variadics_please::all_tuples!(impl_type_hash_tuple, 0, 16, T);
144
145impl<T: TypeHash, const N: usize> TypeHash for [T; N] {
146    fn write_hash(hasher: &mut impl core::hash::Hasher) {
147        hasher.write(b"[;]");
148        hasher.write_usize(N);
149        T::write_hash(hasher);
150    }
151}
152
153impl<T: TypeHash + ?Sized> TypeHash for *const T {
154    fn write_hash(hasher: &mut impl Hasher) {
155        hasher.write(b"*const");
156        T::write_hash(hasher);
157    }
158}
159
160impl<T: TypeHash + ?Sized> TypeHash for *mut T {
161    fn write_hash(hasher: &mut impl Hasher) {
162        hasher.write(b"*mut");
163        T::write_hash(hasher);
164    }
165}
166
167impl<T: TypeHash> TypeHash for [T] {
168    fn write_hash(hasher: &mut impl Hasher) {
169        hasher.write(b"[]");
170        T::write_hash(hasher);
171    }
172}
173
174impl<T: TypeHash + ?Sized> TypeHash for &T {
175    fn write_hash(hasher: &mut impl Hasher) {
176        hasher.write(b"&");
177        T::write_hash(hasher);
178    }
179}
180
181impl<T: TypeHash + ?Sized> TypeHash for &mut T {
182    fn write_hash(hasher: &mut impl Hasher) {
183        hasher.write(b"&mut");
184        T::write_hash(hasher);
185    }
186}
187
188impl<T: TypeHash + ?Sized, U: TypeHash + ?Sized> TypeHash for fn(T) -> U {
189    fn write_hash(hasher: &mut impl Hasher) {
190        hasher.write(b"fn(");
191        T::write_hash(hasher);
192        hasher.write(b") -> ");
193        U::write_hash(hasher);
194    }
195}