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