1use digest::generic_array::{ArrayLength, GenericArray};
10use EndianInput;
11
12use std::borrow::{Cow, ToOwned};
13use std::mem;
14use std::rc::Rc;
15use std::sync::Arc;
16
17pub trait Hash {
31 fn hash<H>(&self, digest: &mut H)
36 where
37 H: EndianInput;
38}
39
40macro_rules! impl_hash_for {
41 {
42 ($self:ident: &$t:ty, $digest:ident)
43 $body:block
44 } => {
45 impl Hash for $t {
46 fn hash<H>(&$self, $digest: &mut H)
47 where H: EndianInput
48 $body
49 }
50 }
51}
52
53macro_rules! impl_hash_for_mi_word {
54 ($t:ty, $_size:expr, $input:ident, $_chain:ident, $_bo_func:ident) => {
55 impl_hash_for! {
56 (self: &$t, digest) {
57 digest.$input(*self);
58 }
59 }
60 };
61}
62
63for_all_mi_words!(impl_hash_for_mi_word!);
64
65impl Hash for u8 {
66 fn hash<H>(&self, digest: &mut H)
67 where
68 H: EndianInput,
69 {
70 digest.input_u8(*self);
71 }
72}
73
74impl Hash for i8 {
75 fn hash<H>(&self, digest: &mut H)
76 where
77 H: EndianInput,
78 {
79 digest.input_i8(*self);
80 }
81}
82
83impl<N> Hash for GenericArray<u8, N>
84where
85 N: ArrayLength<u8>,
86{
87 fn hash<H>(&self, digest: &mut H)
88 where
89 H: EndianInput,
90 {
91 digest.input(self.as_slice());
92 }
93}
94
95impl<N> Hash for GenericArray<i8, N>
96where
97 N: ArrayLength<i8>,
98{
99 fn hash<H>(&self, digest: &mut H)
100 where
101 H: EndianInput,
102 {
103 let bytes: &[u8] = unsafe { mem::transmute(self.as_slice()) };
104 digest.input(bytes);
105 }
106}
107
108impl<'a, T: ?Sized> Hash for &'a T
109where
110 T: Hash,
111{
112 fn hash<H>(&self, digest: &mut H)
113 where
114 H: EndianInput,
115 {
116 (*self).hash(digest);
117 }
118}
119
120macro_rules! impl_hash_for_gen_pointer {
121 ($Ptr:ident<$T:ident>) => {
122 impl<$T: ?Sized> Hash for $Ptr<$T>
123 where
124 $T: Hash,
125 {
126 fn hash<H>(&self, digest: &mut H)
127 where
128 H: EndianInput,
129 {
130 (**self).hash(digest);
131 }
132 }
133 };
134}
135
136impl_hash_for_gen_pointer!(Box<T>);
137impl_hash_for_gen_pointer!(Rc<T>);
138impl_hash_for_gen_pointer!(Arc<T>);
139
140impl<'a, B: ?Sized> Hash for Cow<'a, B>
141where
142 B: Hash,
143 B: ToOwned,
144 B::Owned: Hash,
145{
146 fn hash<H>(&self, digest: &mut H)
147 where
148 H: EndianInput,
149 {
150 match *self {
151 Cow::Borrowed(b) => b.hash(digest),
152 Cow::Owned(ref v) => v.hash(digest),
153 }
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use Hash;
160
161 use testmocks::conv_with;
162 use testmocks::{Hashable, MockDigest};
163 use {BigEndian, LittleEndian};
164
165 use std::borrow::Cow;
166 use std::mem;
167 use std::{f32, f64};
168
169 macro_rules! test_endian_hash {
170 ( $test:ident,
171 $Endian:ident,
172 $val:expr,
173 $to_endian_bits:expr) => {
174 #[test]
175 fn $test() {
176 let mut hasher = $Endian::<MockDigest>::new();
177 ($val).hash(&mut hasher);
178 let output = hasher.into_inner().bytes;
179 let val_bits = conv_with($val, $to_endian_bits);
180 let expected = bytes_from_endian!(val_bits);
181 assert_eq!(output, expected);
182 }
183 };
184 }
185
186 macro_rules! test_byte_hash {
187 ( $be_test:ident,
188 $le_test:ident,
189 $val:expr) => {
190 test_endian_hash!($be_test, BigEndian, $val, |v| v);
191 test_endian_hash!($le_test, LittleEndian, $val, |v| v);
192 };
193 }
194
195 macro_rules! test_word_hash {
196 ( $be_test:ident,
197 $le_test:ident,
198 $val:expr) => {
199 test_word_hash!($be_test, $le_test, $val, |v| v);
200 };
201
202 ( $be_test:ident,
203 $le_test:ident,
204 $val:expr,
205 $conv:expr) => {
206 test_endian_hash!($be_test, BigEndian, $val, |v| conv_with(v, $conv).to_be());
207 test_endian_hash!($le_test, LittleEndian, $val, |v| conv_with(v, $conv)
208 .to_le());
209 };
210 }
211
212 macro_rules! test_float_hash {
213 ( $be_test:ident,
214 $le_test:ident,
215 $val:expr) => {
216 test_word_hash!($be_test, $le_test, $val, |v| v.to_bits());
217 };
218 }
219
220 test_byte_hash!(u8_be_hash, u8_le_hash, 0xA5u8);
221 test_byte_hash!(i8_be_hash, i8_le_hash, -128i8);
222 test_word_hash!(u16_be_hash, u16_le_hash, 0xA55Au16);
223 test_word_hash!(i16_be_hash, i16_le_hash, -0x7FFEi16);
224 test_word_hash!(u32_be_hash, u32_le_hash, 0xA0B0_C0D0u32);
225 test_word_hash!(i32_be_hash, i32_le_hash, -0x7F01_02FDi32);
226 test_word_hash!(u64_be_hash, u64_le_hash, 0xA0B0_C0D0_0102_0304u64);
227 test_word_hash!(i64_be_hash, i64_le_hash, -0x7F01_0203_0405_FFFDi64);
228 test_float_hash!(f32_be_hash, f32_le_hash, f32::consts::PI);
229 test_float_hash!(f64_be_hash, f64_le_hash, f64::consts::PI);
230
231 macro_rules! test_generic_array_hash {
232 ($test:ident, $bt:ty) => {
233 #[test]
234 fn $test() {
235 use digest::generic_array::typenum::consts::U4;
236 use digest::generic_array::GenericArray;
237
238 let array =
239 GenericArray::<$bt, U4>::from_exact_iter((0..4).map(|n| n as $bt)).unwrap();
240 let mut hasher = BigEndian::<MockDigest>::new();
241 array.hash(&mut hasher);
242 let output = hasher.into_inner().bytes;
243 assert_eq!(output, [0, 1, 2, 3]);
244 }
245 };
246 }
247
248 test_generic_array_hash!(generic_array_u8_hash, u8);
249 test_generic_array_hash!(generic_array_i8_hash, i8);
250
251 #[test]
252 fn custom_be_hash() {
253 let v = Hashable {
254 foo: 0x0102,
255 bar: 0x03040506,
256 };
257 let mut hasher = BigEndian::<MockDigest>::new();
258 v.hash(&mut hasher);
259 let output = hasher.into_inner().bytes;
260 assert_eq!(output, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
261 }
262
263 #[test]
264 fn custom_le_hash() {
265 let v = Hashable {
266 foo: 0x0102,
267 bar: 0x03040506,
268 };
269 let mut hasher = LittleEndian::<MockDigest>::new();
270 v.hash(&mut hasher);
271 let output = hasher.into_inner().bytes;
272 assert_eq!(output, [0x02, 0x01, 0x06, 0x05, 0x04, 0x03]);
273 }
274
275 fn test_generic_impl<T: Hash>(v: &T, expected: &[u8]) {
276 let mut hasher = BigEndian::<MockDigest>::new();
277 v.hash(&mut hasher);
278 let output = hasher.into_inner().bytes;
279 assert_eq!(output, expected);
280 }
281
282 #[test]
283 fn ref_hash() {
284 let v = Hashable {
285 foo: 0x0102,
286 bar: 0x03040506,
287 };
288 test_generic_impl(&v, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
289 }
290
291 #[test]
292 fn box_hash() {
293 let v = Box::new(Hashable {
294 foo: 0x0102,
295 bar: 0x03040506,
296 });
297 test_generic_impl(&v, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
298 }
299
300 #[test]
301 fn rc_hash() {
302 use std::rc::Rc;
303
304 let v = Rc::new(Hashable {
305 foo: 0x0102,
306 bar: 0x03040506,
307 });
308 test_generic_impl(&v, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
309 }
310
311 #[test]
312 fn arc_hash() {
313 use std::sync::Arc;
314
315 let v = Arc::new(Hashable {
316 foo: 0x0102,
317 bar: 0x03040506,
318 });
319 test_generic_impl(&v, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
320 }
321
322 #[test]
323 fn cow_borrowed_hash() {
324 let borrowed = &Hashable {
325 foo: 0x0102,
326 bar: 0x03040506,
327 };
328 let cow = Cow::Borrowed(borrowed);
329 let mut hasher = BigEndian::<MockDigest>::new();
330 cow.hash(&mut hasher);
331 let output = hasher.into_inner().bytes;
332 assert_eq!(output, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
333 }
334
335 #[test]
336 fn cow_owned_hash() {
337 let owned = Hashable {
338 foo: 0x0102,
339 bar: 0x03040506,
340 };
341 let cow = Cow::Owned::<Hashable>(owned);
342 let mut hasher = BigEndian::<MockDigest>::new();
343 cow.hash(&mut hasher);
344 let output = hasher.into_inner().bytes;
345 assert_eq!(output, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
346 }
347}