1use multihash::{Harvest, Hash, Multihash};
12use std;
13use std::collections::{BTreeMap, HashMap, HashSet};
14use tag::Tag;
15
16pub trait Blot {
18 fn blot<T: Multihash>(&self, &T) -> Harvest;
19
20 fn digest<D: Multihash>(&self, digester: D) -> Hash<D> {
21 let digest = self.blot(&digester);
22 Hash::new(digester, digest)
23 }
24}
25
26impl<'a, T: ?Sized + Blot> Blot for &'a T {
27 #[inline]
28 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
29 T::blot(*self, digester)
30 }
31}
32
33impl Blot for str {
34 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
35 digester.digest_primitive(Tag::Unicode, self.as_bytes())
36 }
37}
38
39impl Blot for String {
40 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
41 digester.digest_primitive(Tag::Unicode, self.as_bytes())
42 }
43}
44
45impl Blot for [u8] {
46 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
47 digester.digest_primitive(Tag::Raw, self)
48 }
49}
50
51impl<'a, T: Blot> Blot for Option<T> {
52 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
53 match self {
54 None => digester.digest_primitive(Tag::Null, "".as_bytes()),
55 Some(a) => a.blot(digester),
56 }
57 }
58}
59
60impl<'a> Blot for bool {
61 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
62 let string = if *self { "1" } else { "0" };
63 digester.digest_primitive(Tag::Bool, string.as_bytes())
64 }
65}
66
67macro_rules! blot_integer (($type:ident) => {
68 impl Blot for $type {
69 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
70 digester.digest_primitive(Tag::Integer, self.to_string().as_bytes())
71 }
72 }
73});
74
75blot_integer!(u8);
76blot_integer!(u16);
77blot_integer!(u32);
78blot_integer!(u64);
79blot_integer!(usize);
80blot_integer!(i8);
81blot_integer!(i16);
82blot_integer!(i32);
83blot_integer!(i64);
84blot_integer!(isize);
85
86impl<T: Blot> Blot for Vec<T> {
87 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
88 let list: Vec<Vec<u8>> = self
89 .iter()
90 .map(|item| {
91 item.blot(digester)
92 .as_ref()
93 .iter()
94 .map(|x| *x)
95 .collect::<Vec<u8>>()
96 }).collect();
97
98 digester.digest_collection(Tag::List, list)
99 }
100}
101
102impl<T: Blot + Eq + std::hash::Hash> Blot for HashSet<T> {
103 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
104 let mut list: Vec<Vec<u8>> = self
105 .iter()
106 .map(|item| {
107 item.blot(digester)
108 .as_ref()
109 .iter()
110 .map(|x| *x)
111 .collect::<Vec<u8>>()
112 }).collect();
113
114 list.sort_unstable();
115
116 digester.digest_collection(Tag::Set, list)
117 }
118}
119
120impl<K, V> Blot for HashMap<K, V>
121where
122 K: Blot + Eq + std::hash::Hash,
123 V: Blot + PartialEq,
124{
125 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
126 let mut list: Vec<Vec<u8>> = self
127 .iter()
128 .map(|(k, v)| {
129 let mut res: Vec<u8> = Vec::with_capacity(64);
130 res.extend_from_slice(k.blot(digester).as_ref());
131 res.extend_from_slice(v.blot(digester).as_ref());
132
133 res
134 }).collect();
135
136 list.sort_unstable();
137
138 digester.digest_collection(Tag::Dict, list)
139 }
140}
141
142impl<K, V> Blot for BTreeMap<K, V>
143where
144 K: Blot + Eq + std::hash::Hash,
145 V: Blot + PartialEq,
146{
147 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
148 let mut list: Vec<Vec<u8>> = self
149 .iter()
150 .map(|(k, v)| {
151 let mut res: Vec<u8> = Vec::with_capacity(64);
152 res.extend_from_slice(k.blot(digester).as_ref());
153 res.extend_from_slice(v.blot(digester).as_ref());
154
155 res
156 }).collect();
157
158 list.sort_unstable();
159
160 digester.digest_collection(Tag::Dict, list)
161 }
162}
163
164impl Blot for f32 {
165 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
166 (*self as f64).blot(digester)
167 }
168}
169
170impl Blot for f64 {
171 fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
172 if self.is_nan() {
173 digester.digest_primitive(Tag::Float, "NaN".as_bytes())
174 } else if self.is_infinite() {
175 let s = if self.is_sign_negative() {
176 "-Infinity"
177 } else {
178 "Infinity"
179 };
180 digester.digest_primitive(Tag::Float, s.as_bytes())
181 } else {
182 digester.digest_primitive(Tag::Float, float_normalize(*self).as_bytes())
183 }
184 }
185}
186
187pub fn float_normalize(mut f: f64) -> String {
188 if f == 0.0 {
189 return "+0:".to_owned();
190 }
191
192 let mut s = String::new();
193
194 if f < 0. {
196 s.push('-');
197 f = -f;
198 } else {
199 s.push('+');
200 }
201
202 let mut e = 0;
204
205 while f > 1. {
206 f = f / 2.;
207 e = e + 1;
208 }
209
210 while f <= 0.5 {
211 f = f * 2.;
212 e = e - 1;
213 }
214
215 s.push_str(&e.to_string());
216 s.push(':');
217
218 assert!(f <= 1.);
220 assert!(f > 0.5);
221 while f != 0. {
224 if f >= 1. {
225 s.push('1');
226 f = f - 1.;
227 } else {
228 s.push('0');
229 }
230
231 assert!(f < 1.);
232 assert!(s.len() < 1000);
233
234 f = f * 2.;
235 }
236
237 s
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243 use hex::FromHex;
244 use multihash::Sha2256;
245
246 #[test]
247 fn bool_blot_raw() {
248 let expected = "7dc96f776c8423e57a2785489a3f9c43fb6e756876d6ad9a9cac4aa4e72ec193";
249 let actual = true.digest(Sha2256);
250
251 assert_eq!(format!("{}", actual.digest()), expected);
252 }
253
254 #[test]
255 fn unicode_blot() {
256 let pairs = [
257 (
258 "ԱԲաբ",
259 "12202a2a4485a4e338d8df683971956b1090d2f5d33955a81ecaad1a75125f7a316c",
260 ),
261 (
262 "ϓ",
263 "1220f72826713a01881404f34975447bd6edcb8de40b191dc57097ebf4f5417a554d",
264 ),
265 (
266 "foo",
267 "1220a6a6e5e783c363cd95693ec189c2682315d956869397738679b56305f2095038",
268 ),
269 ];
270 for (raw, expected) in pairs.iter() {
271 let actual = format!("{}", raw.digest(Sha2256));
272 assert_eq!(&actual, expected);
273 }
274 }
275
276 #[test]
277 fn null_blot() {
278 let expected = "12201b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9";
279 let actual = format!("{}", None::<String>.digest(Sha2256));
280
281 assert_eq!(actual, expected);
282 }
283
284 #[test]
285 fn raw_blot() {
286 let expected = "1220e318859db4d2acc89c0d503ddbcf8331625125a79018d19cf8f8d1336b7eb39e";
287 let bytes =
288 Vec::from_hex("6b18693874513ba13da54d61aafa7cad0c8f5573f3431d6f1c04b07ddb27d6bb")
289 .unwrap();
290 let actual = format!("{}", (&bytes[..]).digest(Sha2256));
291 assert_eq!(actual, expected);
292 }
293
294 #[test]
295 fn bool_blot() {
296 assert_eq!(
297 format!("{}", true.digest(Sha2256)),
298 "12207dc96f776c8423e57a2785489a3f9c43fb6e756876d6ad9a9cac4aa4e72ec193"
299 );
300 assert_eq!(
301 format!("{}", false.digest(Sha2256)),
302 "1220c02c0b965e023abee808f2b548d8d5193a8b5229be6f3121a6f16e2d41a449b3"
303 );
304 }
305
306 #[test]
307 fn int_blot() {
308 let pairs = [
309 (
310 0,
311 "1220a4e167a76a05add8a8654c169b07b0447a916035aef602df103e8ae0fe2ff390",
312 ),
313 (
314 42,
315 "1220ebc35dc1b8e2602b72beb8d8e5bcdb2babe90f57bcb54ad7282ec798659d2196",
316 ),
317 ];
318 for (raw, expected) in pairs.iter() {
319 let actual = format!("{}", raw.digest(Sha2256));
320 assert_eq!(&actual, expected);
321 }
322 }
323
324 #[test]
325 fn zero_float_blot() {
326 let expected = "122060101d8c9cb988411468e38909571f357daa67bff5a7b0a3f9ae295cd4aba33d";
327 let actual = format!("{}", 0.0.digest(Sha2256));
328 assert_eq!(actual, expected);
329 }
330 #[test]
331 fn float_blot() {
332 use std::f64;
333 let pairs = [
334 (
335 -0.0,
336 "122060101d8c9cb988411468e38909571f357daa67bff5a7b0a3f9ae295cd4aba33d",
337 ),
338 (
339 f64::NAN,
340 "12205d6c301a98d835732d459d7018a8d546872f7ba3c39a45ba481746d2c6d566d9",
341 ),
342 (
343 f64::INFINITY,
344 "1220e0309b2362dc6aaf595338cd9e116761640f74927bcdc4f76e8e6433738f25c7",
345 ),
346 (
347 f64::NEG_INFINITY,
348 "12201167518d5554ba86d9b176af0a57f29d425bedaa9847c245cc397b37533228f7",
349 ),
350 ];
351 for (raw, expected) in pairs.iter() {
352 let actual = format!("{}", raw.digest(Sha2256));
353 assert_eq!(&actual, expected);
354 }
355 }
356
357 #[test]
358 fn empty_list_blot() {
359 let expected = "1220acac86c0e609ca906f632b0e2dacccb2b77d22b0621f20ebece1a4835b93f6f0";
360 let list: Vec<u8> = vec![];
361 let actual = format!("{}", list.digest(Sha2256));
362 assert_eq!(actual, expected);
363 }
364
365 #[test]
366 fn list_blot() {
367 let pairs = [
368 (
369 vec!["foo"],
370 "1220268bc27d4974d9d576222e4cdbb8f7c6bd6791894098645a19eeca9c102d0964",
371 ),
372 (
373 vec!["foo", "bar"],
374 "122032ae896c413cfdc79eec68be9139c86ded8b279238467c216cf2bec4d5f1e4a2",
375 ),
376 ];
377 for (raw, expected) in pairs.iter() {
378 let actual = format!("{}", raw.digest(Sha2256));
379 assert_eq!(&actual, expected);
380 }
381 }
382
383 #[test]
384 fn empty_set_blot() {
385 let expected = "1220043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89";
386 let set: HashSet<u8> = HashSet::new();
387 let actual = format!("{}", set.digest(Sha2256));
388 assert_eq!(actual, expected);
389 }
390
391 #[test]
392 fn set_blot() {
393 let expected = "1220a4fef47742c80337b2eb0dcc6ed36610c93aca0afef86a65f381020b9de2284d";
394 let mut set: HashSet<&str> = HashSet::new();
395 set.insert("foo");
396 let actual = format!("{}", set.digest(Sha2256));
397 assert_eq!(actual, expected);
398 }
399
400 #[test]
401 fn empty_dict_blot() {
402 let expected = "122018ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4";
403 let dict: HashMap<&str, u8> = HashMap::new();
404 let actual = format!("{}", dict.digest(Sha2256));
405 assert_eq!(actual, expected);
406 }
407
408 #[test]
409 fn dict_blot() {
410 let expected = "12207ef5237c3027d6c58100afadf37796b3d351025cf28038280147d42fdc53b960";
411 let mut dict: HashMap<&str, &str> = HashMap::new();
412 dict.insert("foo", "bar");
413 let actual = format!("{}", dict.digest(Sha2256));
414 assert_eq!(actual, expected);
415 }
416}