1#![doc = include_str!("../README.md")]
2#![no_std]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5pub trait TypeSignature {
102 const SIGNATURE: TypeSignatureHasher;
107
108 const CONST_HASH: u64 = Self::SIGNATURE.const_hash();
113}
114
115pub use type_signature_derive::TypeSignature;
116
117#[derive(Debug, Hash)]
122pub struct TypeSignatureHasher {
123 #[doc(hidden)]
125 pub ty_name: &'static str,
126 #[doc(hidden)]
128 pub ty_generics: &'static [&'static TypeSignatureHasher],
129 #[doc(hidden)]
131 pub const_generic_hashes: &'static [u64],
132 #[doc(hidden)]
136 pub variants: &'static [(
137 &'static str,
138 &'static [(&'static str, &'static TypeSignatureHasher)],
139 )],
140}
141impl TypeSignatureHasher {
142 #[must_use]
147 pub const fn const_hash(&self) -> u64 {
148 let mut accumulator = 0x1b61_42dc_8803_64ed;
149
150 __macro_export::mix_values(&mut accumulator, __macro_export::hash_str(self.ty_name));
152
153 {
155 __macro_export::mix_values(&mut accumulator, self.ty_generics.len() as u64);
156 let mut generic_idx = 0;
157 while generic_idx < self.ty_generics.len() {
158 __macro_export::mix_values(
159 &mut accumulator,
160 self.ty_generics[generic_idx].const_hash(),
161 );
162 generic_idx += 1;
163 }
164 }
165
166 {
168 __macro_export::mix_values(&mut accumulator, self.const_generic_hashes.len() as u64);
169 let mut const_generic_idx = 0;
170 while const_generic_idx < self.const_generic_hashes.len() {
171 __macro_export::mix_values(
172 &mut accumulator,
173 self.const_generic_hashes[const_generic_idx],
174 );
175 const_generic_idx += 1;
176 }
177 }
178
179 {
181 __macro_export::mix_values(&mut accumulator, self.variants.len() as u64);
182 let mut variant_idx = 0;
183 while variant_idx < self.variants.len() {
184 let (variant_name, variant_fields) = self.variants[variant_idx];
185 __macro_export::mix_values(
186 &mut accumulator,
187 __macro_export::hash_str(variant_name),
188 );
189 __macro_export::mix_values(&mut accumulator, variant_fields.len() as u64);
190 let mut field_idx = 0;
191 while field_idx < variant_fields.len() {
192 let (field_name, field_hasher) = variant_fields[field_idx];
193 __macro_export::mix_values(
194 &mut accumulator,
195 __macro_export::hash_str(field_name),
196 );
197 __macro_export::mix_values(&mut accumulator, field_hasher.const_hash());
198 field_idx += 1;
199 }
200 variant_idx += 1;
201 }
202 }
203
204 accumulator
205 }
206}
207
208macro_rules! impl_for_stdlib_ty {
210 ($(
211 $stdty:ty $(where < $( $generic:ident $( : $generic_cond:tt )? ),* > )?
212 ),+ $(,)?) => {$(
213 impl$( < $( $generic $( : $generic_cond )? ),* > )? $crate::TypeSignature for $stdty {
214 const SIGNATURE: $crate::TypeSignatureHasher = $crate::TypeSignatureHasher {
215 ty_name: concat!(stringify!($crate::TypeSignature), " impl for ", stringify!($stdty)),
218 ty_generics: &[
219 $( $( &<$generic as $crate::TypeSignature>::SIGNATURE, )* )?
220 ],
221 const_generic_hashes: &[],
222 variants: &[],
224 };
225 }
226 )+};
227}
228
229impl_for_stdlib_ty!(
230 u8, u16, u32, usize, u64, u128,
231 i8, i16, i32, isize, i64, i128,
232 bool,
233 f32,
234 f64,
235 char,
236 str,
237 (),
238 &T where <T: TypeSignature>,
239 &mut T where <T: TypeSignature>,
240 *const T where <T: TypeSignature>,
241 *mut T where <T: TypeSignature>,
242 [T] where <T: TypeSignature>,
243 Option<T> where <T: TypeSignature> ,
244 Result<T, E> where <T: TypeSignature, E: TypeSignature>,
245 core::marker::PhantomData<T> where <T: TypeSignature>,
246 core::mem::MaybeUninit<T> where <T: TypeSignature>,
247 core::mem::ManuallyDrop<T> where <T: TypeSignature>,
248 core::net::IpAddr, core::net::Ipv4Addr, core::net::Ipv6Addr,
249 core::net::SocketAddr, core::net::SocketAddrV4, core::net::SocketAddrV6,
250 core::num::NonZeroU8, core::num::NonZeroU16, core::num::NonZeroU32, core::num::NonZeroU64, core::num::NonZeroUsize, core::num::NonZeroU128,
251 core::num::NonZeroI8, core::num::NonZeroI16, core::num::NonZeroI32, core::num::NonZeroI64, core::num::NonZeroIsize, core::num::NonZeroI128,
252 core::num::Saturating<T> where <T: TypeSignature>,
253 core::num::Wrapping<T> where <T: TypeSignature>,
254 core::ops::Range<T> where <T: TypeSignature>,
255 core::ops::RangeFrom<T> where <T: TypeSignature>,
256 core::ops::RangeFull,
257 core::ops::RangeInclusive<T> where <T: TypeSignature>,
258 core::ops::RangeTo<T> where <T: TypeSignature>,
259 core::ops::RangeToInclusive<T> where <T: TypeSignature>,
260 core::pin::Pin<T> where <T: TypeSignature>,
261 core::ptr::NonNull<T> where <T: TypeSignature>,
262 core::cmp::Ordering,
263 core::convert::Infallible,
264 core::time::Duration,
265);
266
267#[cfg(target_has_atomic = "8")]
268impl_for_stdlib_ty!(
269 core::sync::atomic::AtomicBool,
270 core::sync::atomic::AtomicI8,
271 core::sync::atomic::AtomicU8,
272);
273#[cfg(target_has_atomic = "16")]
274impl_for_stdlib_ty!(core::sync::atomic::AtomicI16, core::sync::atomic::AtomicU16);
275#[cfg(target_has_atomic = "32")]
276impl_for_stdlib_ty!(core::sync::atomic::AtomicI32, core::sync::atomic::AtomicU32);
277#[cfg(target_has_atomic = "64")]
278impl_for_stdlib_ty!(core::sync::atomic::AtomicI64, core::sync::atomic::AtomicU64);
279#[cfg(target_has_atomic = "ptr")]
280impl_for_stdlib_ty!(
281 core::sync::atomic::AtomicIsize,
282 core::sync::atomic::AtomicUsize,
283 core::sync::atomic::AtomicPtr<T> where <T: TypeSignature>,
284);
285
286impl<const N: usize, T: TypeSignature> TypeSignature for [T; N] {
287 const SIGNATURE: TypeSignatureHasher = TypeSignatureHasher {
288 ty_name: "TypeSignature impl for [T; N]",
289 ty_generics: &[&T::SIGNATURE],
290 const_generic_hashes: &[__macro_export::hash_const_usize(N)],
291 variants: &[],
293 };
294}
295
296macro_rules! impl_for_tuple {
298 ($(
299 ( $( $elem_ty:ident, )* $(,)? )
300 ),+ $(,)? ) => {$(
301
302 impl< $( $elem_ty ),* > TypeSignature for ($($elem_ty,)*)
303 where $( $elem_ty : TypeSignature ),*
304 {
305 const SIGNATURE: TypeSignatureHasher = TypeSignatureHasher {
306 ty_name: concat!(stringify!($crate::TypeSignature), " impl for (", $( stringify!($elem_ty), "," ),* ),
307 ty_generics: &[
308 $( &<$elem_ty as $crate::TypeSignature>::SIGNATURE, )*
309 ],
310 const_generic_hashes: &[],
311 variants: &[],
313 };
314 }
315
316 )+};
317}
318
319impl_for_tuple!(
320 (T0,),
321 (T0, T1,),
322 (T0, T1, T2,),
323 (T0, T1, T2, T3,),
324 (T0, T1, T2, T3, T4,),
325 (T0, T1, T2, T3, T4, T5,),
326 (T0, T1, T2, T3, T4, T5, T6,),
327 (T0, T1, T2, T3, T4, T5, T6, T7,),
328 (T0, T1, T2, T3, T4, T5, T6, T7, T8,),
329 (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9,),
330 (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,),
331 (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,),
332 (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,),
333 (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,),
334 (
335 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
336 ),
337 (
338 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
339 ),
340);
341
342#[cfg(feature = "std")]
343#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
344mod std_impl {
345 extern crate std;
346
347 use crate::TypeSignature;
348
349 impl_for_stdlib_ty!(
350 std::collections::HashMap<K, V> where <K: TypeSignature, V: TypeSignature>,
351 std::collections::HashSet<T> where <T: TypeSignature>,
352 std::ffi::OsStr,
353 std::ffi::OsString,
354 std::path::Path,
355 std::path::PathBuf,
356 std::sync::Mutex<T> where <T: TypeSignature>,
357 std::sync::RwLock<T> where <T: TypeSignature>,
358 std::sync::Once,
359 std::time::Instant,
360 std::time::SystemTime,
361 );
362}
363
364#[cfg(feature = "alloc")]
365#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
366mod alloc_impl {
367 extern crate alloc;
368
369 use crate::TypeSignature;
370
371 impl_for_stdlib_ty!(
372 alloc::boxed::Box<T> where <T: TypeSignature>,
373 alloc::collections::BinaryHeap<T> where <T: TypeSignature>,
374 alloc::collections::BTreeMap<K, V> where <K: TypeSignature, V: TypeSignature>,
375 alloc::collections::BTreeSet<T> where <T: TypeSignature>,
376 alloc::collections::LinkedList<T> where <T: TypeSignature>,
377 alloc::collections::VecDeque<T> where <T: TypeSignature>,
378 alloc::ffi::CString,
379 alloc::rc::Rc<T> where <T: TypeSignature>,
380 alloc::rc::Weak<T> where <T: TypeSignature>,
381 alloc::string::String,
382 alloc::vec::Vec<T> where <T: TypeSignature>,
383 );
384
385 #[cfg(target_has_atomic = "ptr")]
386 impl_for_stdlib_ty!(
387 alloc::sync::Arc<T> where <T: TypeSignature>,
388 alloc::sync::Weak<T> where <T: TypeSignature>,
389 );
390
391 impl<'a, B: TypeSignature + alloc::borrow::ToOwned + ?Sized + 'a> TypeSignature
392 for alloc::borrow::Cow<'a, B>
393 {
394 const SIGNATURE: crate::TypeSignatureHasher = crate::TypeSignatureHasher {
395 ty_name: "TypeSignature impl for Cow<'a, B>",
396 ty_generics: &[&<B as TypeSignature>::SIGNATURE],
397 const_generic_hashes: &[],
398 variants: &[],
399 };
400 }
401}
402
403#[macro_export]
459macro_rules! impl_type_signature_as {
460 ($target:ident as struct { $( $fields:tt )* }) => {
461 $crate::_impl_ts_as_helper! { $target as $target in struct $target { $( $fields )* } }
462 };
463 ($target:ident as enum { $( $variants:tt )* }) => {
464 $crate::_impl_ts_as_helper! { $target as $target in enum $target { $( $variants )* } }
465 };
466}
467
468#[doc(hidden)]
472pub mod __macro_export {
473 #[must_use]
475 pub const fn hash_const_usize(param_val: usize) -> u64 {
476 let mut accumulator = hash_str("usize");
477 mix_values(&mut accumulator, param_val as u64);
478 if size_of::<usize>() == 16 {
480 mix_values(&mut accumulator, ((param_val as u128) >> 64) as u64);
481 }
482 accumulator
483 }
484
485 #[must_use]
487 pub const fn hash_const_bool(param_val: bool) -> u64 {
488 let mut accumulator = hash_str("bool");
489 mix_values(
490 &mut accumulator,
491 if param_val {
493 0x7907_e475_126f_2049
494 } else {
495 0xa656_face_e66f_d217
496 },
497 );
498 accumulator
499 }
500
501 pub const fn mix_values(accumulator: &mut u64, value: u64) {
506 *accumulator = accumulator
509 .wrapping_mul(0x35ce_5fac_9b48_99b5)
510 .wrapping_add(0x1e5d_49b9_70ea_d075)
511 ^ value
512 .wrapping_mul(0x13fd_608d_551c_c1d1)
513 .wrapping_add(0x87b5_2407_45ca_ca0f);
514 }
515
516 #[must_use]
521 pub const fn hash_str(s: &str) -> u64 {
522 let mut accumulator = 0x1124_262e_5999_d5bb;
523 mix_values(&mut accumulator, s.len() as u64);
524 let mut byte_idx = 0;
525 while byte_idx < s.len() {
526 mix_values(&mut accumulator, s.as_bytes()[byte_idx] as u64);
527 byte_idx += 1;
528 }
529 accumulator
530 }
531
532 #[doc(hidden)]
534 #[macro_export]
535 macro_rules! _impl_ts_as_helper {
536 ($target:ty as $ident:ident in $item:item) => {
537 impl $crate::TypeSignature for $target {
538 const SIGNATURE: $crate::TypeSignatureHasher = {
539 #[derive($crate::TypeSignature)]
540 #[type_signature(crate = $crate)]
541 #[allow(dead_code)]
542 $item
543
544 $ident::SIGNATURE
545 };
546 }
547 };
548 }
549}
550
551#[cfg(test)]
552mod tests {
553 use super::*;
554
555 #[derive(TypeSignature)]
556 #[type_signature(crate = super)]
557 #[allow(dead_code, reason = "Schema depends on it")]
558 struct Foo {
559 bar: u32,
560 }
561
562 #[test]
563 fn test_derive_with_custom_crate_name() {
564 assert_eq!(Foo::CONST_HASH, 0x9cb2_d1de_e1dc_8ae3);
565 }
566}