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    pliron::value::Value,
129);
130
131macro_rules! impl_type_hash_tuple {
132    ($($T: ident),*) => {
133        impl <$($T: $crate::TypeHash),*> TypeHash for ($($T,)*) {
134            fn write_hash(hasher: &mut impl core::hash::Hasher) {
135                hasher.write(b"()");
136                $(
137                    $T::write_hash(hasher);
138                )*
139            }
140        }
141    };
142}
143
144variadics_please::all_tuples!(impl_type_hash_tuple, 0, 16, T);
145
146impl<T: TypeHash, const N: usize> TypeHash for [T; N] {
147    fn write_hash(hasher: &mut impl core::hash::Hasher) {
148        hasher.write(b"[;]");
149        hasher.write_usize(N);
150        T::write_hash(hasher);
151    }
152}
153
154impl<T: TypeHash + ?Sized> TypeHash for *const T {
155    fn write_hash(hasher: &mut impl Hasher) {
156        hasher.write(b"*const");
157        T::write_hash(hasher);
158    }
159}
160
161impl<T: TypeHash + ?Sized> TypeHash for *mut T {
162    fn write_hash(hasher: &mut impl Hasher) {
163        hasher.write(b"*mut");
164        T::write_hash(hasher);
165    }
166}
167
168impl<T: TypeHash> TypeHash for [T] {
169    fn write_hash(hasher: &mut impl Hasher) {
170        hasher.write(b"[]");
171        T::write_hash(hasher);
172    }
173}
174
175impl<T: TypeHash + ?Sized> TypeHash for &T {
176    fn write_hash(hasher: &mut impl Hasher) {
177        hasher.write(b"&");
178        T::write_hash(hasher);
179    }
180}
181
182impl<T: TypeHash + ?Sized> TypeHash for &mut T {
183    fn write_hash(hasher: &mut impl Hasher) {
184        hasher.write(b"&mut");
185        T::write_hash(hasher);
186    }
187}
188
189impl<T: TypeHash + ?Sized, U: TypeHash + ?Sized> TypeHash for fn(T) -> U {
190    fn write_hash(hasher: &mut impl Hasher) {
191        hasher.write(b"fn(");
192        T::write_hash(hasher);
193        hasher.write(b") -> ");
194        U::write_hash(hasher);
195    }
196}