rune_core/
hash.rs
1pub use self::into_hash::IntoHash;
2mod into_hash;
3
4pub use self::to_type_hash::ToTypeHash;
5mod to_type_hash;
6
7use core::fmt;
8use core::hash::{BuildHasher, BuildHasherDefault, Hash as _, Hasher};
9
10#[cfg(feature = "musli")]
11use musli::{Decode, Encode};
12use serde::{Deserialize, Serialize};
13use twox_hash::XxHash64;
14
15#[derive(Debug)]
16#[non_exhaustive]
17pub struct TooManyParameters;
18
19impl fmt::Display for TooManyParameters {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 write!(f, "Only 32 type parameters are supported")
22 }
23}
24
25impl core::error::Error for TooManyParameters {}
26
27use crate::alloc;
28use crate::alloc::clone::TryClone;
29
30const SEP: u64 = 0x4bc94d6bd06053ad;
31const TYPE: u64 = 0x2fac10b63a6cc57c;
32const ASSOCIATED_FUNCTION_HASH: u64 = 0x5ea77ffbcdf5f302;
33const OBJECT_KEYS: u64 = 0x4473d7017aef7645;
34const IDENT: u64 = 0x1a095090689d4647;
35const INDEX: u64 = 0xe1b2378d7a937035;
36const TYPE_PARAMETERS: u32 = 16;
38const FUNCTION_PARAMETERS: u32 = 48;
40const PARAMETERS: [u64; 32] = [
42 0x2d859a05306ebe33,
43 0x75ac929aabdda742,
44 0x18f4e51cd6f60e86,
45 0x3b47f977015b002,
46 0xd7e3b9e36d59b900,
47 0xad75a1d63593d47c,
48 0x8fc37a65ac89ed71,
49 0x39eb9ab133d1cf22,
50 0xa287885efb6bf688,
51 0x9eeef0c7395ea8ca,
52 0x26a193328114c317,
53 0x9edc35591d044a28,
54 0xbfa4e9a8eca88b80,
55 0x94a626c6aa89a686,
56 0x95970296235c5b91,
57 0xa8ab16ceff9068b8,
58 0x153e675e2a27db85,
59 0xa873a7e51dfe4205,
60 0xde401d82396a7876,
61 0x9dbbae67606eddc3,
62 0x23d51f8018d09e74,
63 0xb5bfa5d588fedcc6,
64 0x9702480ba16eeb96,
65 0x58549fb39441505c,
66 0xd88078065e88667d,
67 0x38a1d4efb147fe18,
68 0xf712c95e9ffd1ba5,
69 0x73c2249b2845a5e0,
70 0x8079aff8b0833e20,
71 0x7e708fb5e906bbb5,
72 0x22d363b1d55a5eec,
73 0x9e2d56cbbd4459f1,
74];
75
76#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
79#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))]
80#[repr(transparent)]
81pub struct Hash(#[doc(hidden)] pub u64);
82
83impl Hash {
84 pub const EMPTY: Self = Self(0);
86
87 #[doc(hidden)]
89 pub const fn new(hash: u64) -> Self {
90 Self(hash)
91 }
92
93 #[doc(hidden)]
95 pub const fn new_with_type_parameters(hash: u64, parameters: Hash) -> Self {
96 Self(hash).with_type_parameters(parameters)
97 }
98
99 #[inline]
101 pub fn as_non_empty(&self) -> Option<Self> {
102 if self.is_empty() {
103 None
104 } else {
105 Some(*self)
106 }
107 }
108
109 #[doc(hidden)]
111 pub const fn into_inner(self) -> u64 {
112 self.0
113 }
114
115 #[doc(hidden)]
117 pub const fn is_empty(&self) -> bool {
118 self.0 == 0
119 }
120
121 #[inline]
123 pub fn index(index: usize) -> Self {
124 Self(INDEX ^ (index as u64))
125 }
126
127 pub fn ident(name: &str) -> Hash {
130 let mut hasher = Self::new_hasher();
131 name.hash(&mut hasher);
132 Self(IDENT ^ hasher.finish())
133 }
134
135 pub fn type_hash(path: impl ToTypeHash) -> Self {
137 path.to_type_hash()
138 }
139
140 #[inline]
143 pub fn associated_function(type_hash: impl IntoHash, name: impl IntoHash) -> Self {
144 let type_hash = type_hash.into_hash();
145 let name = name.into_hash();
146 Self(ASSOCIATED_FUNCTION_HASH ^ (type_hash.0 ^ name.0))
147 }
148
149 #[inline]
151 pub fn field_function(protocol: impl IntoHash, type_hash: Hash, name: impl IntoHash) -> Self {
152 let protocol = protocol.into_hash();
153 Self::associated_function(Hash(type_hash.0 ^ protocol.0), name)
154 }
155
156 #[inline]
158 pub fn index_function(protocol: impl IntoHash, type_hash: Hash, index: Hash) -> Self {
159 let protocol = protocol.into_hash();
160 Self::associated_function(Hash(type_hash.0 ^ protocol.0), index)
161 }
162
163 pub fn static_bytes(bytes: &[u8]) -> Hash {
165 let mut hasher = Self::new_hasher();
166 bytes.hash(&mut hasher);
167 Self(hasher.finish())
168 }
169
170 pub fn object_keys<I>(keys: I) -> Self
172 where
173 I: IntoIterator,
174 I::Item: AsRef<str>,
175 {
176 let mut hasher = Self::new_hasher();
177 OBJECT_KEYS.hash(&mut hasher);
178
179 for key in keys {
180 SEP.hash(&mut hasher);
181 key.as_ref().hash(&mut hasher);
182 }
183
184 Self(hasher.finish())
185 }
186
187 pub const fn with_generics(self, generics: Self) -> Self {
192 Self(self.0 ^ generics.0)
193 }
194
195 pub const fn with_type_parameters(self, ty: Self) -> Self {
197 Self(self.0 ^ ty.0.wrapping_shl(TYPE_PARAMETERS))
198 }
199
200 pub const fn with_function_parameters(self, f: Self) -> Self {
202 Self(self.0 ^ f.0.wrapping_shl(FUNCTION_PARAMETERS))
203 }
204
205 pub const fn parameters<const N: usize>(params: [Hash; N]) -> Self {
207 let mut builder = ParametersBuilder::new();
208
209 while builder.index < N {
210 let param = params[builder.index];
211
212 let Ok(b) = builder.add(param) else {
213 panic!("Only up to 32 type parameters are supported");
214 };
215
216 builder = b;
217 }
218
219 builder.finish()
220 }
221
222 fn new_hasher() -> XxHash64 {
224 BuildHasherDefault::<XxHash64>::default().build_hasher()
225 }
226}
227
228impl TryClone for Hash {
229 fn try_clone(&self) -> alloc::Result<Self> {
230 Ok(*self)
231 }
232}
233
234impl fmt::Display for Hash {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 write!(f, "0x{:x}", self.0)
237 }
238}
239
240impl fmt::Debug for Hash {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 write!(f, "0x{:x}", self.0)
243 }
244}
245
246#[derive(Default)]
268pub struct ParametersBuilder {
269 base: u64,
270 index: usize,
271 shift: u32,
272}
273
274impl ParametersBuilder {
275 pub const fn new() -> Self {
277 Self {
278 base: 0,
279 index: 0,
280 shift: 0,
281 }
282 }
283
284 pub const fn add(mut self, Hash(hash): Hash) -> Result<Self, TooManyParameters> {
290 if self.index >= PARAMETERS.len() {
291 self.shift += 8;
292 self.index = 0;
293
294 if self.shift >= u64::BITS {
295 return Err(TooManyParameters);
296 }
297 }
298
299 self.base ^= hash ^ PARAMETERS[self.index].wrapping_shl(self.shift);
300 self.index += 1;
301 Ok(self)
302 }
303
304 pub const fn finish(self) -> Hash {
306 Hash::new(self.base)
307 }
308}