32
33
/// A binary object ID.
34
#[repr(C)]
35
-#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
35
+#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
36
pub struct ObjectID {
37
pub hash: [u8; GIT_MAX_RAWSZ],
38
pub algo: u32,
40
41
#[allow(dead_code)]
42
impl ObjectID {
43
+ /// Return a new object ID with the given algorithm and hash.
44
+ ///
45
+ /// `hash` must be exactly the proper length for `algo` and this function panics if it is not.
46
+ /// The extra internal storage of `hash`, if any, is zero filled.
47
+ pub fn new(algo: HashAlgorithm, hash: &[u8]) -> Self {
48
+ let mut data = [0u8; GIT_MAX_RAWSZ];
49
+ // This verifies that the length of `hash` is correct.
50
+ data[0..algo.raw_len()].copy_from_slice(hash);
51
+ Self {
52
+ hash: data,
53
+ algo: algo as u32,
54
+ }
55
+ }
56
+
57
+ /// Return the algorithm for this object ID.
58
+ ///
59
+ /// If the algorithm set internally is not valid, this function panics.
60
+ pub fn algo(&self) -> Result<HashAlgorithm, InvalidHashAlgorithm> {
61
+ HashAlgorithm::from_u32(self.algo).ok_or(InvalidHashAlgorithm(self.algo))
62
+ }
63
+
64
pub fn as_slice(&self) -> Result<&[u8], InvalidHashAlgorithm> {
65
match HashAlgorithm::from_u32(self.algo) {
66
Some(algo) => Ok(&self.hash[0..algo.raw_len()]),
76
}
77
}
78
79
+impl Display for ObjectID {
80
+ /// Format this object ID as a hex object ID.
81
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82
+ let hash = self.as_slice().unwrap();
83
+ for x in hash {
84
+ write!(f, "{:02x}", x)?;
85
+ }
86
+ Ok(())
87
+ }
88
+}
89
+
90
+impl Debug for ObjectID {
91
+ /// Format this object ID as a hex object ID with a colon and name appended to it.
92
+ ///
93
+ /// ```
94
+ /// assert_eq!(
95
+ /// format!("{:?}", HashAlgorithm::SHA256.null_oid()),
96
+ /// "0000000000000000000000000000000000000000000000000000000000000000:sha256"
97
+ /// );
98
+ /// ```
99
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100
+ let hash = match self.as_slice() {
101
+ Ok(hash) => hash,
102
+ Err(_) => &self.hash,
103
+ };
104
+ for x in hash {
105
+ write!(f, "{:02x}", x)?;
106
+ }
107
+ match self.algo() {
108
+ Ok(algo) => write!(f, ":{}", algo.name()),
109
+ Err(e) => write!(f, ":invalid-hash-algo-{}", e.0),
110
+ }
111
+ }
112
+}
113
+
114
/// A hash algorithm,
115
#[repr(C)]
116
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
248
pub fn hash_algo_ptr_by_number(n: u32) -> *const c_void;
249
}
250
}
251
+
252
+#[cfg(test)]
253
+mod tests {
254
+ use super::HashAlgorithm;
255
+
256
+ fn all_algos() -> &'static [HashAlgorithm] {
257
+ &[HashAlgorithm::SHA1, HashAlgorithm::SHA256]
258
+ }
259
+
260
+ #[test]
261
+ fn format_id_round_trips() {
262
+ for algo in all_algos() {
263
+ assert_eq!(
264
+ *algo,
265
+ HashAlgorithm::from_format_id(algo.format_id()).unwrap()
266
+ );
267
+ }
268
+ }
269
+
270
+ #[test]
271
+ fn offset_round_trips() {
272
+ for algo in all_algos() {
273
+ assert_eq!(*algo, HashAlgorithm::from_u32(*algo as u32).unwrap());
274
+ }
275
+ }
276
+
277
+ #[test]
278
+ fn slices_have_correct_length() {
279
+ for algo in all_algos() {
280
+ for oid in [algo.null_oid(), algo.empty_blob(), algo.empty_tree()] {
281
+ assert_eq!(oid.as_slice().unwrap().len(), algo.raw_len());
282
+ }
283
+ }
284
+ }
285
+
286
+ #[test]
287
+ fn object_ids_format_correctly() {
288
+ let entries = &[
289
+ (
290
+ HashAlgorithm::SHA1.null_oid(),
291
+ "0000000000000000000000000000000000000000",
292
+ "0000000000000000000000000000000000000000:sha1",
293
+ ),
294
+ (
295
+ HashAlgorithm::SHA1.empty_blob(),
296
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
297
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391:sha1",
298
+ ),
299
+ (
300
+ HashAlgorithm::SHA1.empty_tree(),
301
+ "4b825dc642cb6eb9a060e54bf8d69288fbee4904",
302
+ "4b825dc642cb6eb9a060e54bf8d69288fbee4904:sha1",
303
+ ),
304
+ (
305
+ HashAlgorithm::SHA256.null_oid(),
306
+ "0000000000000000000000000000000000000000000000000000000000000000",
307
+ "0000000000000000000000000000000000000000000000000000000000000000:sha256",
308
+ ),
309
+ (
310
+ HashAlgorithm::SHA256.empty_blob(),
311
+ "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813",
312
+ "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813:sha256",
313
+ ),
314
+ (
315
+ HashAlgorithm::SHA256.empty_tree(),
316
+ "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321",
317
+ "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321:sha256",
318
+ ),
319
+ ];
320
+ for (oid, display, debug) in entries {
321
+ assert_eq!(format!("{}", oid), *display);
322
+ assert_eq!(format!("{:?}", oid), *debug);
323
+ }
324
+ }
325
+}