Skip to main content

gix_object/
data.rs

1//! Contains a borrowed Object bound to a buffer holding its decompressed data.
2
3use crate::{BlobRef, CommitRef, CommitRefIter, Data, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter};
4
5impl<'a> Data<'a> {
6    /// Constructs a new data object from `data`, `kind` and `object_hash`.
7    pub fn new(data: &'a [u8], kind: Kind, hash_kind: gix_hash::Kind) -> Data<'a> {
8        Data {
9            kind,
10            object_hash: hash_kind,
11            data,
12        }
13    }
14    /// Decodes the data in the backing slice into a [`ObjectRef`], allowing to access all of its data
15    /// conveniently. The cost of parsing an object is negligible.
16    ///
17    /// **Note** that [mutable, decoded objects][crate::Object] can be created from [`Data`]
18    /// using [`crate::ObjectRef::into_owned()`].
19    pub fn decode(&self) -> Result<ObjectRef<'a>, crate::decode::Error> {
20        Ok(match self.kind {
21            Kind::Tree => ObjectRef::Tree(TreeRef::from_bytes(self.data, self.object_hash)?),
22            Kind::Blob => ObjectRef::Blob(BlobRef { data: self.data }),
23            Kind::Commit => ObjectRef::Commit(CommitRef::from_bytes(self.data, self.object_hash)?),
24            Kind::Tag => ObjectRef::Tag(TagRef::from_bytes(self.data, self.object_hash)?),
25        })
26    }
27
28    /// Returns this object as tree iterator to parse entries one at a time to avoid allocations, or
29    /// `None` if this is not a tree object.
30    pub fn try_into_tree_iter(self) -> Option<TreeRefIter<'a>> {
31        match self.kind {
32            Kind::Tree => Some(TreeRefIter::from_bytes(self.data, self.object_hash)),
33            _ => None,
34        }
35    }
36
37    /// Returns this object as commit iterator to parse tokens one at a time to avoid allocations, or
38    /// `None` if this is not a commit object.
39    pub fn try_into_commit_iter(self) -> Option<CommitRefIter<'a>> {
40        match self.kind {
41            Kind::Commit => Some(CommitRefIter::from_bytes(self.data, self.object_hash)),
42            _ => None,
43        }
44    }
45
46    /// Returns this object as tag iterator to parse tokens one at a time to avoid allocations, or
47    /// `None` if this is not a tag object.
48    pub fn try_into_tag_iter(self) -> Option<TagRefIter<'a>> {
49        match self.kind {
50            Kind::Tag => Some(TagRefIter::from_bytes(self.data, self.object_hash)),
51            _ => None,
52        }
53    }
54}
55
56/// Types supporting object hash verification
57pub mod verify {
58    /// Returned by [`crate::Data::verify_checksum()`]
59    #[derive(Debug, thiserror::Error)]
60    #[allow(missing_docs)]
61    pub enum Error {
62        #[error("Failed to hash object")]
63        Hasher(#[from] gix_hash::hasher::Error),
64        #[error(transparent)]
65        Verify(#[from] gix_hash::verify::Error),
66    }
67
68    impl crate::Data<'_> {
69        /// Compute the checksum of `self` and compare it with the `expected` hash.
70        /// If the hashes do not match, an [`Error`] is returned, containing the actual
71        /// hash of `self`.
72        pub fn verify_checksum(&self, expected: &gix_hash::oid) -> Result<gix_hash::ObjectId, Error> {
73            let actual = crate::compute_hash(expected.kind(), self.kind, self.data)?;
74            actual.verify(expected)?;
75            Ok(actual)
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn size_of_object() {
86        #[cfg(target_pointer_width = "64")]
87        assert_eq!(std::mem::size_of::<Data<'_>>(), 24, "this shouldn't change unnoticed");
88        #[cfg(target_pointer_width = "32")]
89        assert_eq!(std::mem::size_of::<Data<'_>>(), 12, "this shouldn't change unnoticed");
90    }
91}