1#![no_std]
48
49extern crate alloc;
50
51pub use sails_reflect_hash_derive::ReflectHash;
53
54#[doc(hidden)]
56pub use keccak_const;
57
58use alloc::{collections::BTreeMap, string::String, vec::Vec};
59use core::num::{
60 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroU8, NonZeroU16, NonZeroU32,
61 NonZeroU64, NonZeroU128,
62};
63use gprimitives::{ActorId, CodeId, H160, H256, MessageId, NonZeroU256, U256};
64use keccak_const::Keccak256;
65
66pub trait ReflectHash {
76 const HASH: [u8; 32];
78}
79
80macro_rules! impl_reflect_hash_for_primitives {
81 ($($t:ty => $discriminant:literal),* $(,)?) => {
82 $(
83 impl ReflectHash for $t {
84 const HASH: [u8; 32] = Keccak256::new()
85 .update($discriminant)
86 .finalize();
87 }
88 )*
89 };
90}
91
92impl_reflect_hash_for_primitives! {
95 u8 => b"u8",
96 u16 => b"u16",
97 u32 => b"u32",
98 u64 => b"u64",
99 u128 => b"u128",
100 i8 => b"i8",
101 i16 => b"i16",
102 i32 => b"i32",
103 i64 => b"i64",
104 i128 => b"i128",
105 bool => b"bool",
106 char => b"char",
107 str => b"String",
108 String => b"String",
109}
110
111impl ReflectHash for NonZeroU8 {
112 const HASH: [u8; 32] = Keccak256::new()
113 .update(b"NonZeroU8")
114 .update(&<u8 as ReflectHash>::HASH)
115 .finalize();
116}
117
118impl ReflectHash for NonZeroU16 {
119 const HASH: [u8; 32] = Keccak256::new()
120 .update(b"NonZeroU16")
121 .update(&<u16 as ReflectHash>::HASH)
122 .finalize();
123}
124
125impl ReflectHash for NonZeroU32 {
126 const HASH: [u8; 32] = Keccak256::new()
127 .update(b"NonZeroU32")
128 .update(&<u32 as ReflectHash>::HASH)
129 .finalize();
130}
131
132impl ReflectHash for NonZeroU64 {
133 const HASH: [u8; 32] = Keccak256::new()
134 .update(b"NonZeroU64")
135 .update(&<u64 as ReflectHash>::HASH)
136 .finalize();
137}
138
139impl ReflectHash for NonZeroU128 {
140 const HASH: [u8; 32] = Keccak256::new()
141 .update(b"NonZeroU128")
142 .update(&<u128 as ReflectHash>::HASH)
143 .finalize();
144}
145
146impl ReflectHash for NonZeroI8 {
147 const HASH: [u8; 32] = Keccak256::new()
148 .update(b"NonZeroI8")
149 .update(&<i8 as ReflectHash>::HASH)
150 .finalize();
151}
152
153impl ReflectHash for NonZeroI16 {
154 const HASH: [u8; 32] = Keccak256::new()
155 .update(b"NonZeroI16")
156 .update(&<i16 as ReflectHash>::HASH)
157 .finalize();
158}
159
160impl ReflectHash for NonZeroI32 {
161 const HASH: [u8; 32] = Keccak256::new()
162 .update(b"NonZeroI32")
163 .update(&<i32 as ReflectHash>::HASH)
164 .finalize();
165}
166
167impl ReflectHash for NonZeroI64 {
168 const HASH: [u8; 32] = Keccak256::new()
169 .update(b"NonZeroI64")
170 .update(&<i64 as ReflectHash>::HASH)
171 .finalize();
172}
173
174impl ReflectHash for NonZeroI128 {
175 const HASH: [u8; 32] = Keccak256::new()
176 .update(b"NonZeroI128")
177 .update(&<i128 as ReflectHash>::HASH)
178 .finalize();
179}
180
181impl<T: ReflectHash> ReflectHash for [T] {
183 const HASH: [u8; 32] = {
184 Keccak256::new()
185 .update(b"[")
186 .update(&T::HASH)
187 .update(b"]")
188 .finalize()
189 };
190}
191
192impl<T: ReflectHash + ?Sized> ReflectHash for &T {
195 const HASH: [u8; 32] = T::HASH;
196}
197
198impl<T: ReflectHash + ?Sized> ReflectHash for &mut T {
201 const HASH: [u8; 32] = T::HASH;
202}
203
204impl ReflectHash for () {
205 const HASH: [u8; 32] = Keccak256::new().update(b"()").finalize();
206}
207
208impl<T: ReflectHash> ReflectHash for Option<T> {
209 const HASH: [u8; 32] = {
210 Keccak256::new()
211 .update(b"Option")
212 .update(&T::HASH)
213 .finalize()
214 };
215}
216
217impl<T: ReflectHash, E: ReflectHash> ReflectHash for Result<T, E> {
218 const HASH: [u8; 32] = {
219 Keccak256::new()
220 .update(b"Result")
221 .update(&T::HASH)
222 .update(&E::HASH)
223 .finalize()
224 };
225}
226
227macro_rules! impl_reflect_hash_for_tuples {
228 () => {};
229 ($first:ident $(, $rest:ident)*) => {
230 impl<$first: ReflectHash, $($rest: ReflectHash),*> ReflectHash for ($first, $($rest),*) {
231 const HASH: [u8; 32] = {
232 Keccak256::new()
233 .update(&$first::HASH)
234 $(
235 .update(&$rest::HASH)
236 )*
237 .finalize()
238 };
239 }
240 impl_reflect_hash_for_tuples!($($rest),*);
241 };
242}
243
244impl_reflect_hash_for_tuples!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
246
247macro_rules! impl_reflect_hash_for_bytes_arrays {
248 ($($n:expr),* $(,)?) => {
249 $(
250 impl<T: ReflectHash> ReflectHash for [T; $n] {
251 const HASH: [u8; 32] = {
252 let n_str = stringify!($n);
253 Keccak256::new()
254 .update(&T::HASH)
255 .update(n_str.as_bytes())
256 .finalize()
257 };
258 }
259 )*
260 };
261}
262
263impl_reflect_hash_for_bytes_arrays!(
265 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
266 26, 27, 28, 29, 30, 31, 32,
267);
268
269impl ReflectHash for ActorId {
270 const HASH: [u8; 32] = Keccak256::new().update(b"ActorId").finalize();
271}
272
273impl ReflectHash for MessageId {
274 const HASH: [u8; 32] = Keccak256::new().update(b"MessageId").finalize();
275}
276
277impl ReflectHash for CodeId {
278 const HASH: [u8; 32] = Keccak256::new().update(b"CodeId").finalize();
279}
280
281impl ReflectHash for H256 {
282 const HASH: [u8; 32] = Keccak256::new().update(b"H256").finalize();
283}
284
285impl ReflectHash for H160 {
286 const HASH: [u8; 32] = Keccak256::new().update(b"H160").finalize();
287}
288
289impl ReflectHash for U256 {
290 const HASH: [u8; 32] = Keccak256::new().update(b"U256").finalize();
291}
292
293impl ReflectHash for NonZeroU256 {
294 const HASH: [u8; 32] = Keccak256::new()
295 .update(b"NonZeroU256")
296 .update(&U256::HASH)
297 .finalize();
298}
299
300impl<T: ReflectHash> ReflectHash for Vec<T> {
301 const HASH: [u8; 32] = {
302 Keccak256::new()
303 .update(b"[")
304 .update(&T::HASH)
305 .update(b"]")
306 .finalize()
307 };
308}
309
310impl<K: ReflectHash, V: ReflectHash> ReflectHash for BTreeMap<K, V> {
311 const HASH: [u8; 32] = {
312 Keccak256::new()
313 .update(b"[")
314 .update(&<(K, V) as ReflectHash>::HASH)
315 .update(b"]")
316 .finalize()
317 };
318}
319
320#[cfg(test)]
321mod tests {
322 use super::*;
323
324 #[test]
325 fn same_hash_types() {
326 assert_eq!(str::HASH, String::HASH);
327 assert_eq!(<[u8] as ReflectHash>::HASH, Vec::<u8>::HASH);
328 assert_eq!(<&u32 as ReflectHash>::HASH, u32::HASH);
329 assert_eq!(<&mut u32 as ReflectHash>::HASH, u32::HASH);
330 assert_eq!(<&'static str as ReflectHash>::HASH, str::HASH);
331 }
332
333 #[test]
335 fn crate_paths() {
336 use crate as reflect_hash_crate;
337
338 #[derive(ReflectHash)]
339 #[reflect_hash(crate = reflect_hash_crate)]
340 #[allow(dead_code)]
341 struct TestStruct(String);
342 }
343}