tysh/
lib.rs

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
33/// A type for which its metadata is hashable.
34///
35/// Consider using `#[derive(`[`TypeHash`](derive.TypeHash.html)`)]` before implementing this trait directly.
36pub trait TypeHash {
37    /// Hashes the type metadata.
38    ///
39    /// # Example
40    ///
41    /// ```rust
42    /// use std::collections::hash_map::DefaultHasher;
43    ///
44    /// # use tysh::TypeHash;
45    /// #
46    /// #[derive(TypeHash)]
47    /// pub struct A {
48    ///     a: u8,
49    ///     b: u16,
50    /// }
51    ///
52    /// let mut hasher = DefaultHasher::new();
53    /// A::type_hash(&mut hasher);
54    /// ```
55    fn type_hash<H: Hasher>(hasher: &mut H);
56
57    /// Returns a hash value of the type metadata.
58    ///
59    /// ## Example
60    ///
61    /// ```rust
62    /// use std::collections::hash_map::DefaultHasher;
63    ///
64    /// # use tysh::TypeHash;
65    /// #
66    /// #[derive(TypeHash)]
67    /// pub struct A {
68    ///     a: u8,
69    ///     b: u16,
70    /// }
71    ///
72    /// dbg!(A::type_hash_one::<DefaultHasher>());
73    /// ```
74    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")]
97/// This can be used when the `int128` feature is enabled.
98impl 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")]
109/// This can be used when the `int128` feature is enabled.
110impl 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")]
126/// This can be used when the `int128` feature is enabled.
127impl 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")]
138/// This can be used when the `int128` feature is enabled.
139impl 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")]
147/// This can be used when the `alloc` feature is enabled.
148impl 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")]
182/// This can be used when the `alloc` feature is enabled.
183impl<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")]
192/// This can be used when the `std` feature is enabled.
193impl<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")]
202/// This can be used when the `std` feature is enabled.
203impl<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);