Coverage Report

Created: 2024-02-20 21:15

/builds/xfbs/cindy/common/src/hash.rs
Line
Count
Source (jump to first uncovered line)
1
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
2
use std::{
3
    borrow::{Borrow, ToOwned},
4
    fmt::{Display, Formatter, Result as FmtResult},
5
    ops::Deref,
6
    rc::Rc,
7
    str::FromStr,
8
    sync::Arc,
9
};
10
11
/// Represents a hash value with generic storage.
12
47.0k
#[derive(
Clone10
, Copy,
Debug0
, Eq, PartialOrd,
Ord14
,
Hash0
)]
13
pub struct Hash<T: ?Sized + AsRef<[u8]> = [u8]>(T);
14
15
impl Hash {
16
47.9k
    pub fn new<H: AsRef<[u8]> + ?Sized>(hash: &H) -> &Self {
17
47.9k
        unsafe { &*(hash.as_ref() as *const [u8] as *const Hash) }
18
47.9k
    }
19
}
20
21
impl<T: ?Sized + AsRef<[u8]>> Hash<T> {
22
62.1k
    pub fn as_slice(&self) -> &[u8] {
23
62.1k
        self.0.as_ref()
24
62.1k
    }
25
}
26
27
impl<T: Sized + AsRef<[u8]>> Deref for Hash<T> {
28
    type Target = Hash;
29
30
6.39k
    fn deref(&self) -> &Self::Target {
31
6.39k
        Hash::new(&self.0)
32
6.39k
    }
33
}
34
35
impl Deref for Hash {
36
    type Target = [u8];
37
38
17
    fn deref(&self) -> &Self::Target {
39
17
        &self.0
40
17
    }
41
}
42
43
pub type BoxHash = Hash<Box<[u8]>>;
44
pub type ArcHash = Hash<Arc<[u8]>>;
45
pub type RcHash = Hash<Rc<[u8]>>;
46
pub type RefHash<'a> = Hash<&'a [u8]>;
47
48
impl<T: AsRef<[u8]> + ?Sized> AsRef<Hash> for Hash<T> {
49
3
    fn as_ref(&self) -> &Hash {
50
3
        Hash::<[u8]>::new::<T>(&self.0)
51
3
    }
52
}
53
54
impl<T: AsRef<[u8]>> From<T> for Hash<T> {
55
28.4k
    fn from(value: T) -> Self {
56
28.4k
        Self(value)
57
28.4k
    }
58
}
59
60
impl<T: ?Sized + AsRef<[u8]>> Display for Hash<T> {
61
62
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
62
62
        let slice = self.0.as_ref();
63
3.72k
        for 
byte3.66k
in slice {
64
3.66k
            write!(f, "{:02x}", byte)
?0
;
65
        }
66
62
        Ok(())
67
62
    }
68
}
69
70
impl<T: ?Sized + AsRef<[u8]>> AsRef<[u8]> for Hash<T> {
71
0
    fn as_ref(&self) -> &[u8] {
72
0
        self.0.as_ref()
73
0
    }
74
}
75
76
impl<T: AsRef<[u8]> + From<Vec<u8>>> From<&Hash> for Hash<T> {
77
16
    fn from(hash: &Hash) -> Self {
78
16
        Self(hash.0.to_vec().into())
79
16
    }
80
}
81
82
impl<T: AsRef<[u8]> + From<Vec<u8>>> FromStr for Hash<T> {
83
    type Err = hex::FromHexError;
84
13
    fn from_str(input: &str) -> Result<Self, Self::Err> {
85
13
        hex::decode(input).map(Into::into).map(Self)
86
13
    }
87
}
88
89
impl<L: ?Sized + AsRef<[u8]>, R: ?Sized + AsRef<[u8]>> PartialEq<Hash<R>> for Hash<L> {
90
26.8k
    fn eq(&self, other: &Hash<R>) -> bool {
91
26.8k
        self.0.as_ref().eq(other.0.as_ref())
92
26.8k
    }
93
}
94
95
impl<T: ?Sized + AsRef<[u8]>> PartialEq<[u8]> for Hash<T> {
96
1
    fn eq(&self, other: &[u8]) -> bool {
97
1
        self.0.as_ref().eq(other)
98
1
    }
99
}
100
101
impl<T: ?Sized + AsRef<[u8]>, const L: usize> PartialEq<[u8; L]> for Hash<T> {
102
26
    fn eq(&self, other: &[u8; L]) -> bool {
103
26
        self.0.as_ref().eq(&other[..])
104
26
    }
105
}
106
107
impl<T: AsRef<[u8]>> Serialize for Hash<T> {
108
4
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109
4
    where
110
4
        S: Serializer,
111
4
    {
112
4
        // serialize as hex string or as byte array, depending on format.
113
4
        if serializer.is_human_readable() {
114
3
            self.to_string().serialize(serializer)
115
        } else {
116
1
            self.0.as_ref().serialize(serializer)
117
        }
118
4
    }
119
}
120
121
impl<'de, T: AsRef<[u8]> + From<Vec<u8>>> Deserialize<'de> for Hash<T> {
122
13
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
123
13
    where
124
13
        D: Deserializer<'de>,
125
13
    {
126
13
        if deserializer.is_human_readable() {
127
11
            let data: &'de str = <&'de str>::deserialize(deserializer)
?0
;
128
11
            Ok(Self::from_str(data).map_err(Error::custom)
?0
)
129
        } else {
130
2
            let data: Vec<u8> = <Vec<u8>>::deserialize(deserializer)
?0
;
131
2
            Ok(Self(data.into()))
132
        }
133
13
    }
134
}
135
136
impl<T: AsRef<[u8]>> Borrow<Hash> for Hash<T> {
137
14
    fn borrow(&self) -> &Hash {
138
14
        Hash::new(self.0.as_ref())
139
14
    }
140
}
141
142
impl ToOwned for Hash {
143
    type Owned = Hash<Box<[u8]>>;
144
145
0
    fn to_owned(&self) -> Self::Owned {
146
0
        Hash(Box::from(self.0.to_vec()))
147
0
    }
148
}
149
150
impl<T: AsRef<[u8]>> From<&T> for BoxHash {
151
3
    fn from(value: &T) -> Self {
152
3
        Hash(value.as_ref().to_vec().into())
153
3
    }
154
}
155
156
impl From<BoxHash> for ArcHash {
157
2
    fn from(hash: BoxHash) -> Self {
158
2
        Self(hash.0.into())
159
2
    }
160
}
161
162
impl From<BoxHash> for RcHash {
163
2
    fn from(hash: BoxHash) -> Self {
164
2
        Self(hash.0.into())
165
2
    }
166
}
167
168
#[cfg(test)]
169
mod tests {
170
    use super::*;
171
    use serde_test::{assert_tokens, Configure, Token};
172
173
1
    #[test]
174
1
    fn test_serialize() {
175
1
        assert_tokens(
176
1
            &BoxHash::from(Box::<[u8]>::from(vec![0xde, 0xad, 0xbe, 0xef])).readable(),
177
1
            &[Token::BorrowedStr("deadbeef")],
178
1
        );
179
1
180
1
        assert_tokens(
181
1
            &BoxHash::from(Box::<[u8]>::from(vec![0xde, 0xad, 0xbe, 0xef])).compact(),
182
1
            &[
183
1
                Token::Seq { len: Some(4) },
184
1
                Token::U8(0xde),
185
1
                Token::U8(0xad),
186
1
                Token::U8(0xbe),
187
1
                Token::U8(0xef),
188
1
                Token::SeqEnd,
189
1
            ],
190
1
        );
191
1
    }
192
193
1
    #[test]
194
1
    fn hash_new() {
195
1
        let hash_value = [0xde, 0xad, 0xbe, 0xef];
196
1
        let hash = Hash::new(&hash_value);
197
1
        assert_eq!(*hash, hash_value);
198
1
    }
199
200
1
    #[test]
201
1
    fn hash_eq_slice() {
202
1
        let hash_value = [0xde, 0xad, 0xbe, 0xef];
203
1
        let hash = Hash::new(&hash_value);
204
1
        assert_eq!(*hash, hash_value[..]);
205
1
    }
206
207
1
    #[test]
208
1
    fn hash_from_box_hash() {
209
1
        let hash_value = [0xde, 0xad, 0xbe, 0xef];
210
1
        let box_hash = BoxHash::from(Box::<[u8]>::from(hash_value));
211
1
        let hash: &Hash = &box_hash;
212
1
        assert_eq!(*hash, hash_value);
213
1
    }
214
215
1
    #[test]
216
1
    fn box_hash_from_string() {
217
1
        let hash: BoxHash = "deadbeef".parse().unwrap();
218
1
        assert_eq!(hash, [0xde, 0xad, 0xbe, 0xef]);
219
1
    }
220
221
1
    #[test]
222
1
    fn arc_hash_from_string() {
223
1
        let hash: ArcHash = "deadbeef".parse().unwrap();
224
1
        assert_eq!(hash, [0xde, 0xad, 0xbe, 0xef]);
225
1
    }
226
227
1
    #[test]
228
1
    fn hash_to_string() {
229
1
        assert_eq!(Hash::from([0xde, 0xad, 0xbe, 0xef]).to_string(), "deadbeef");
230
1
    }
231
232
1
    #[test]
233
1
    fn box_hash_from() {
234
1
        let box_hash = BoxHash::from(&[12, 23, 56, 67]);
235
1
        assert_eq!(box_hash, [12, 23, 56, 67]);
236
1
    }
237
238
1
    #[test]
239
1
    fn box_hash_into() {
240
1
        let box_hash = BoxHash::from(&[12, 23, 56, 67]);
241
1
        let arc_hash: ArcHash = box_hash.clone().into();
242
1
        assert_eq!(box_hash, arc_hash);
243
1
        let rc_hash: RcHash = box_hash.clone().into();
244
1
        assert_eq!(box_hash, rc_hash);
245
1
    }
246
247
1
    #[test]
248
1
    fn hash_as_ref() {
249
1
        let hash_data = [1, 2, 3, 4];
250
1
251
1
        let box_hash = BoxHash::from(&hash_data);
252
1
        let hash: &Hash = box_hash.as_ref();
253
1
        assert_eq!(*hash, hash_data);
254
255
1
        let rc_hash = RcHash::from(box_hash.clone());
256
1
        let hash: &Hash = rc_hash.as_ref();
257
1
        assert_eq!(*hash, hash_data);
258
259
1
        let arc_hash = ArcHash::from(box_hash.clone());
260
1
        let hash: &Hash = arc_hash.as_ref();
261
1
        assert_eq!(*hash, hash_data);
262
1
    }
263
}