1#![cfg_attr(not(feature = "std"), no_std)]
2#![doc = include_str!("../README.md")]
3#![warn(clippy::all, clippy::nursery, missing_docs)]
4
5#[cfg(all(feature = "smallvec", not(feature = "alloc")))]
6compile_error!("smallvec feature requires std or alloc feature");
7
8#[cfg(all(feature = "alloc", not(feature = "std")))]
9extern crate alloc;
10
11#[cfg(all(feature = "alloc", not(feature = "std")))]
12use alloc::{string::String, vec::Vec};
13#[cfg(feature = "int128")]
14use core::num::{NonZeroI128, NonZeroU128};
15use core::{
16 hash::{Hash, Hasher},
17 num::{
18 NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64,
19 NonZeroU8,
20 },
21};
22#[cfg(feature = "std")]
23use std::collections::{HashMap, HashSet};
24
25mod same_type;
26
27pub use same_type::SameTypeHash;
28pub use tysh_derive::TypeHash;
29
30const PRIMITIVE: &str = "@primitive@";
31const STANDARD: &str = "@standard@";
32
33pub trait TypeHash {
37 fn type_hash<H: Hasher>(hasher: &mut H);
56
57 fn type_hash_one<H: Default + Hasher>() -> u64 {
75 let mut hasher = H::default();
76 Self::type_hash(&mut hasher);
77 hasher.finish()
78 }
79}
80
81macro_rules! impl_for_primitive {
82 ($t:ty) => {
83 impl TypeHash for $t {
84 fn type_hash<H: Hasher>(hasher: &mut H) {
85 PRIMITIVE.hash(hasher);
86 stringify!($t).hash(hasher);
87 }
88 }
89 };
90}
91
92impl_for_primitive!(u8);
93impl_for_primitive!(u16);
94impl_for_primitive!(u32);
95impl_for_primitive!(u64);
96#[cfg(feature = "int128")]
97impl TypeHash for u128 {
99 fn type_hash<H: Hasher>(hasher: &mut H) {
100 PRIMITIVE.hash(hasher);
101 stringify!(u128).hash(hasher);
102 }
103}
104impl_for_primitive!(i8);
105impl_for_primitive!(i16);
106impl_for_primitive!(i32);
107impl_for_primitive!(i64);
108#[cfg(feature = "int128")]
109impl TypeHash for i128 {
111 fn type_hash<H: Hasher>(hasher: &mut H) {
112 PRIMITIVE.hash(hasher);
113 stringify!(i128).hash(hasher);
114 }
115}
116impl_for_primitive!(f32);
117impl_for_primitive!(f64);
118impl_for_primitive!(bool);
119impl_for_primitive!(char);
120
121impl_for_primitive!(NonZeroU8);
122impl_for_primitive!(NonZeroU16);
123impl_for_primitive!(NonZeroU32);
124impl_for_primitive!(NonZeroU64);
125#[cfg(feature = "int128")]
126impl TypeHash for NonZeroU128 {
128 fn type_hash<H: Hasher>(hasher: &mut H) {
129 PRIMITIVE.hash(hasher);
130 stringify!(NonZeroU128).hash(hasher);
131 }
132}
133impl_for_primitive!(NonZeroI8);
134impl_for_primitive!(NonZeroI16);
135impl_for_primitive!(NonZeroI32);
136impl_for_primitive!(NonZeroI64);
137#[cfg(feature = "int128")]
138impl TypeHash for NonZeroI128 {
140 fn type_hash<H: Hasher>(hasher: &mut H) {
141 PRIMITIVE.hash(hasher);
142 stringify!(NonZeroI128).hash(hasher);
143 }
144}
145
146#[cfg(feature = "alloc")]
147impl TypeHash for String {
149 fn type_hash<H: Hasher>(hasher: &mut H) {
150 STANDARD.hash(hasher);
151 stringify!(String).hash(hasher);
152 }
153}
154
155impl<T: TypeHash> TypeHash for Option<T> {
156 fn type_hash<H: Hasher>(hasher: &mut H) {
157 STANDARD.hash(hasher);
158 "Option".hash(hasher);
159 T::type_hash(hasher);
160 }
161}
162
163impl<T: TypeHash, E: TypeHash> TypeHash for Result<T, E> {
164 fn type_hash<H: Hasher>(hasher: &mut H) {
165 STANDARD.hash(hasher);
166 "Result".hash(hasher);
167 T::type_hash(hasher);
168 E::type_hash(hasher);
169 }
170}
171
172impl<const N: usize, T: TypeHash> TypeHash for [T; N] {
173 fn type_hash<H: Hasher>(hasher: &mut H) {
174 STANDARD.hash(hasher);
175 "Array".hash(hasher);
176 N.hash(hasher);
177 T::type_hash(hasher);
178 }
179}
180
181#[cfg(feature = "alloc")]
182impl<T: TypeHash> TypeHash for Vec<T> {
184 fn type_hash<H: Hasher>(hasher: &mut H) {
185 STANDARD.hash(hasher);
186 "Vec".hash(hasher);
187 T::type_hash(hasher);
188 }
189}
190
191#[cfg(feature = "std")]
192impl<T: TypeHash> TypeHash for HashSet<T> {
194 fn type_hash<H: Hasher>(hasher: &mut H) {
195 STANDARD.hash(hasher);
196 "Set".hash(hasher);
197 T::type_hash(hasher);
198 }
199}
200
201#[cfg(feature = "std")]
202impl<T: TypeHash, U: TypeHash> TypeHash for HashMap<T, U> {
204 fn type_hash<H: Hasher>(hasher: &mut H) {
205 STANDARD.hash(hasher);
206 "Map".hash(hasher);
207 T::type_hash(hasher);
208 U::type_hash(hasher);
209 }
210}
211
212macro_rules! impl_for_tuple {
213 ($($xs:ident),+ $(,)?) => {
214 impl<$($xs),+> TypeHash for ($($xs),+)
215 where
216 $($xs: TypeHash),+
217 {
218 fn type_hash<H: Hasher>(hasher: &mut H) {
219 STANDARD.hash(hasher);
220 "Tuple".hash(hasher);
221 $(
222 $xs::type_hash(hasher);
223 )+
224 }
225 }
226 };
227}
228
229impl<T1: TypeHash> SameTypeHash for (T1,) {
230 type Target = T1;
231}
232
233impl_for_tuple!(T1, T2);
234impl_for_tuple!(T1, T2, T3);
235impl_for_tuple!(T1, T2, T3, T4);
236impl_for_tuple!(T1, T2, T3, T4, T5);
237impl_for_tuple!(T1, T2, T3, T4, T5, T6);
238impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7);
239impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);
240impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
241impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
242impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
243impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
244impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
245impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
246impl_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);