1pub use macros::*;
5
6use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
7use std::num::NonZeroU64;
8use std::ops::Range;
9
10pub trait TypeFingerprint {
13 fn fingerprint() -> String;
14}
15
16macro_rules! impl_fprint_simple {
18 ($($($type: ident)::*),*) => {
19 $(
20 impl TypeFingerprint for $($type)::* {
21 fn fingerprint() -> String { stringify!($($type)::*).to_string() }
22 }
23 )*
24 };
25}
26
27impl_fprint_simple!(
28 bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, str, String,
29 NonZeroU64
30);
31
32macro_rules! impl_fprint_array {
34 ($n: literal) => {
35 impl<T: TypeFingerprint> TypeFingerprint for [T; $n] {
36 fn fingerprint() -> String {
37 "[".to_string() + &T::fingerprint() + ";" + stringify!($n) + "]"
38 }
39 }
40 };
41}
42
43impl_fprint_array!(0);
44impl_fprint_array!(1);
45impl_fprint_array!(2);
46impl_fprint_array!(3);
47impl_fprint_array!(4);
48impl_fprint_array!(5);
49impl_fprint_array!(6);
50impl_fprint_array!(7);
51impl_fprint_array!(8);
52impl_fprint_array!(9);
53impl_fprint_array!(10);
54impl_fprint_array!(11);
55impl_fprint_array!(12);
56impl_fprint_array!(13);
57impl_fprint_array!(14);
58impl_fprint_array!(15);
59impl_fprint_array!(16);
60impl_fprint_array!(17);
61impl_fprint_array!(18);
62impl_fprint_array!(19);
63impl_fprint_array!(20);
64impl_fprint_array!(21);
65impl_fprint_array!(22);
66impl_fprint_array!(23);
67impl_fprint_array!(24);
68impl_fprint_array!(25);
69impl_fprint_array!(26);
70impl_fprint_array!(27);
71impl_fprint_array!(28);
72impl_fprint_array!(29);
73impl_fprint_array!(30);
74impl_fprint_array!(31);
75impl_fprint_array!(32);
76
77macro_rules! impl_fprint_one_generic {
78 ($($($type: ident)::*),*) => {
79 $(
80 impl<T: TypeFingerprint> TypeFingerprint for $($type)::*<T> {
81 fn fingerprint() -> String {
82 "".to_owned() + stringify!($($type)::*) + "<" + &T::fingerprint() + ">"
83 }
84 }
85 )*
86 };
87}
88
89impl_fprint_one_generic!(BTreeSet, HashSet, Range, Option, Vec, bit_vec::BitVec);
90
91macro_rules! impl_fprint_two_generic {
92 ($($($type: ident)::*),*) => {
93 $(
94 impl<A: TypeFingerprint, B: TypeFingerprint> TypeFingerprint for $($type)::*<A,B> {
95 fn fingerprint() -> String {
96 "".to_owned() + stringify!($($type)::*) +
97 "<" + &A::fingerprint() + "," + &B::fingerprint() + ">"
98 }
99 }
100 )*
101 };
102}
103
104impl_fprint_two_generic!(BTreeMap);
105
106macro_rules! impl_fprint_tuple {
107 (($($type: ident,)*)) => {
108 impl<$($type: TypeFingerprint),*> TypeFingerprint for ($($type,)*) {
109 fn fingerprint() -> String {
110 "(".to_owned() + $(&$type::fingerprint() + "," +)* ")"
111 }
112 }
113 };
114}
115
116impl_fprint_tuple!(());
117impl_fprint_tuple!((A,));
118impl_fprint_tuple!((A, B,));
119impl_fprint_tuple!((A, B, C,));
120impl_fprint_tuple!((A, B, C, D,));
121impl_fprint_tuple!((A, B, C, D, E,));
122impl_fprint_tuple!((A, B, C, D, E, F,));
123impl_fprint_tuple!((A, B, C, D, E, F, G,));
124impl_fprint_tuple!((A, B, C, D, E, F, G, H,));
125impl_fprint_tuple!((A, B, C, D, E, F, G, H, I,));
126
127impl<'a, T: TypeFingerprint + ?Sized> TypeFingerprint for &'a T {
128 fn fingerprint() -> String {
129 "&".to_owned() + &T::fingerprint()
130 }
131}
132
133impl<'a, T: TypeFingerprint + ?Sized> TypeFingerprint for &'a mut T {
134 fn fingerprint() -> String {
135 "&mut".to_owned() + &T::fingerprint()
136 }
137}
138
139impl<T: TypeFingerprint> TypeFingerprint for [T] {
140 fn fingerprint() -> String {
141 "[".to_owned() + &T::fingerprint() + "]"
142 }
143}
144
145impl<T: TypeFingerprint + ?Sized> TypeFingerprint for Box<T> {
146 fn fingerprint() -> String {
147 "Box<".to_owned() + &T::fingerprint() + ">"
148 }
149}
150
151impl<K: TypeFingerprint, V: TypeFingerprint, S> TypeFingerprint for HashMap<K, V, S> {
152 fn fingerprint() -> String {
153 "HashMap<".to_owned() + &K::fingerprint() + "," + &V::fingerprint() + ">"
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use crate::*;
162 struct Foo {}
163 impl TypeFingerprint for Foo {
164 fn fingerprint() -> String {
165 "Foo".to_string()
166 }
167 }
168
169 #[derive(TypeFingerprint)]
170 struct Bar(Foo);
171
172 #[allow(dead_code)]
174 #[derive(TypeFingerprint)]
175 struct Baz {
176 foo: Foo,
177 bar: Bar,
178 bizz: u64,
179 }
180
181 #[allow(dead_code)]
183 #[derive(TypeFingerprint)]
184 enum Buzz {
185 A(Foo),
186 B(Bar),
187 C(Baz),
188 }
189
190 #[test]
191 fn test_simple() {
192 assert_eq!(u32::fingerprint(), "u32");
193 }
194
195 #[test]
196 fn test_array() {
197 assert_eq!(<[u32; 3]>::fingerprint(), "[u32;3]");
198 }
199
200 #[test]
201 fn test_vec() {
202 assert_eq!(Vec::<[u32; 3]>::fingerprint(), "Vec<[u32;3]>");
203 }
204
205 #[test]
206 fn test_hashmap_and_tuple() {
207 assert_eq!(
208 std::collections::HashMap::<[u32; 3], (bool, [u64; 8])>::fingerprint(),
209 "HashMap<[u32;3],(bool,[u64;8],)>"
210 );
211 }
212
213 #[test]
214 fn test_hand_implemented() {
215 assert_eq!(Foo::fingerprint(), "Foo");
216 }
217
218 #[test]
219 fn test_struct() {
220 assert_eq!(Bar::fingerprint(), "struct {Foo}");
221 assert_eq!(Baz::fingerprint(), "struct {foo:Foo,bar:struct {Foo},bizz:u64}");
222 }
223
224 #[test]
225 fn test_enum() {
226 assert_eq!(
227 Buzz::fingerprint(),
228 "enum {A(Foo),B(struct {Foo}),C(struct {foo:Foo,bar:struct {Foo},bizz:u64})}"
229 );
230 }
231
232 mod custom_serializer {
233 pub fn fingerprint<T>() -> String {
234 "custom_fingerprint".to_string()
235 }
236 }
237
238 #[allow(dead_code)]
239 #[derive(TypeFingerprint)]
240 struct TestWithSerde {
241 #[serde(with = "custom_serializer")]
242 value: u64,
243 }
244
245 #[allow(dead_code)]
246 #[derive(TypeFingerprint)]
247 struct TestWithMultipleSerdeAttrs {
248 #[serde(default, rename = "some_value", with = "custom_serializer")]
249 value: u64,
250 }
251
252 #[allow(dead_code)]
253 #[derive(TypeFingerprint)]
254 struct TestWithListSerdeAttrs {
255 #[serde(rename(serialize = "foo", deserialize = "bar"), with = "custom_serializer")]
256 value: u64,
257 }
258
259 #[test]
260 fn test_serde_with() {
261 assert_eq!(TestWithSerde::fingerprint(), "struct {value:custom_fingerprint}");
262 assert_eq!(TestWithMultipleSerdeAttrs::fingerprint(), "struct {value:custom_fingerprint}");
263 assert_eq!(TestWithListSerdeAttrs::fingerprint(), "struct {value:custom_fingerprint}");
264 }
265}