equal
deleted
inserted
replaced
|
1 use rand::{thread_rng, RngCore}; |
|
2 use std::fmt::{Formatter, LowerHex}; |
|
3 |
|
4 #[derive(PartialEq, Debug)] |
|
5 pub struct Sha1Digest([u8; 20]); |
|
6 |
|
7 impl Sha1Digest { |
|
8 pub fn new(digest: [u8; 20]) -> Self { |
|
9 Self(digest) |
|
10 } |
|
11 |
|
12 pub fn random() -> Self { |
|
13 let mut result = Sha1Digest(Default::default()); |
|
14 thread_rng().fill_bytes(&mut result.0); |
|
15 result |
|
16 } |
|
17 } |
|
18 |
|
19 impl LowerHex for Sha1Digest { |
|
20 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { |
|
21 for byte in &self.0 { |
|
22 write!(f, "{:02x}", byte)?; |
|
23 } |
|
24 Ok(()) |
|
25 } |
|
26 } |
|
27 |
|
28 impl PartialEq<&str> for Sha1Digest { |
|
29 fn eq(&self, other: &&str) -> bool { |
|
30 if other.len() != self.0.len() * 2 { |
|
31 false |
|
32 } else { |
|
33 #[inline] |
|
34 fn convert(c: u8) -> u8 { |
|
35 if c > b'9' { |
|
36 c.wrapping_sub(b'a').saturating_add(10) |
|
37 } else { |
|
38 c.wrapping_sub(b'0') |
|
39 } |
|
40 } |
|
41 |
|
42 other |
|
43 .as_bytes() |
|
44 .chunks_exact(2) |
|
45 .zip(&self.0) |
|
46 .all(|(chars, byte)| { |
|
47 if let [hi, lo] = chars { |
|
48 convert(*lo) == byte & 0x0f && convert(*hi) == (byte & 0xf0) >> 4 |
|
49 } else { |
|
50 unreachable!() |
|
51 } |
|
52 }) |
|
53 } |
|
54 } |
|
55 } |