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