/// A binary object ID.
#[repr(C)]
-#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
+#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct ObjectID {
pub hash: [u8; GIT_MAX_RAWSZ],
pub algo: u32,
#[allow(dead_code)]
impl ObjectID {
+ /// Return a new object ID with the given algorithm and hash.
+ ///
+ /// `hash` must be exactly the proper length for `algo` and this function panics if it is not.
+ /// The extra internal storage of `hash`, if any, is zero filled.
+ pub fn new(algo: HashAlgorithm, hash: &[u8]) -> Self {
+ let mut data = [0u8; GIT_MAX_RAWSZ];
+ // This verifies that the length of `hash` is correct.
+ data[0..algo.raw_len()].copy_from_slice(hash);
+ Self {
+ hash: data,
+ algo: algo as u32,
+ }
+ }
+
+ /// Return the algorithm for this object ID.
+ ///
+ /// If the algorithm set internally is not valid, this function panics.
+ pub fn algo(&self) -> Result<HashAlgorithm, InvalidHashAlgorithm> {
+ HashAlgorithm::from_u32(self.algo).ok_or(InvalidHashAlgorithm(self.algo))
+ }
+
pub fn as_slice(&self) -> Result<&[u8], InvalidHashAlgorithm> {
match HashAlgorithm::from_u32(self.algo) {
Some(algo) => Ok(&self.hash[0..algo.raw_len()]),
}
}
+impl Display for ObjectID {
+ /// Format this object ID as a hex object ID.
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let hash = self.as_slice().unwrap();
+ for x in hash {
+ write!(f, "{:02x}", x)?;
+ }
+ Ok(())
+ }
+}
+
+impl Debug for ObjectID {
+ /// Format this object ID as a hex object ID with a colon and name appended to it.
+ ///
+ /// ```
+ /// assert_eq!(
+ /// format!("{:?}", HashAlgorithm::SHA256.null_oid()),
+ /// "0000000000000000000000000000000000000000000000000000000000000000:sha256"
+ /// );
+ /// ```
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let hash = match self.as_slice() {
+ Ok(hash) => hash,
+ Err(_) => &self.hash,
+ };
+ for x in hash {
+ write!(f, "{:02x}", x)?;
+ }
+ match self.algo() {
+ Ok(algo) => write!(f, ":{}", algo.name()),
+ Err(e) => write!(f, ":invalid-hash-algo-{}", e.0),
+ }
+ }
+}
+
/// A hash algorithm,
#[repr(C)]
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub fn hash_algo_ptr_by_number(n: u32) -> *const c_void;
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::HashAlgorithm;
+
+ fn all_algos() -> &'static [HashAlgorithm] {
+ &[HashAlgorithm::SHA1, HashAlgorithm::SHA256]
+ }
+
+ #[test]
+ fn format_id_round_trips() {
+ for algo in all_algos() {
+ assert_eq!(
+ *algo,
+ HashAlgorithm::from_format_id(algo.format_id()).unwrap()
+ );
+ }
+ }
+
+ #[test]
+ fn offset_round_trips() {
+ for algo in all_algos() {
+ assert_eq!(*algo, HashAlgorithm::from_u32(*algo as u32).unwrap());
+ }
+ }
+
+ #[test]
+ fn slices_have_correct_length() {
+ for algo in all_algos() {
+ for oid in [algo.null_oid(), algo.empty_blob(), algo.empty_tree()] {
+ assert_eq!(oid.as_slice().unwrap().len(), algo.raw_len());
+ }
+ }
+ }
+
+ #[test]
+ fn object_ids_format_correctly() {
+ let entries = &[
+ (
+ HashAlgorithm::SHA1.null_oid(),
+ "0000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000:sha1",
+ ),
+ (
+ HashAlgorithm::SHA1.empty_blob(),
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391:sha1",
+ ),
+ (
+ HashAlgorithm::SHA1.empty_tree(),
+ "4b825dc642cb6eb9a060e54bf8d69288fbee4904",
+ "4b825dc642cb6eb9a060e54bf8d69288fbee4904:sha1",
+ ),
+ (
+ HashAlgorithm::SHA256.null_oid(),
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000:sha256",
+ ),
+ (
+ HashAlgorithm::SHA256.empty_blob(),
+ "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813",
+ "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813:sha256",
+ ),
+ (
+ HashAlgorithm::SHA256.empty_tree(),
+ "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321",
+ "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321:sha256",
+ ),
+ ];
+ for (oid, display, debug) in entries {
+ assert_eq!(format!("{}", oid), *display);
+ assert_eq!(format!("{:?}", oid), *debug);
+ }
+ }
+}