209 lines · 6.2 KB · Rust
RawDownload
//!#![allow(clippy::empty_docs)]use std::ops::Deref; use gix_hash::{ObjectId, oid}; use crate::{Id, Object, object::find}; /// An [object id][ObjectId] infused with a [`Repository`][crate::Repository].impl<'repo> Id<'repo> {    /// Find the [`Object`] associated with this object id, and consider it an error if it doesn't exist.    ///    /// # Note    ///    /// There can only be one `ObjectRef` per `Easy`. To increase that limit, clone the `Easy`.    pub fn object(&self) -> Result<Object<'repo>, find::existing::Error> {        self.repo.find_object(self.inner)    }     /// Find the [`header`][gix_odb::find::Header] associated with this object id, or an error if it doesn't exist.    ///    /// Use this method if there is no interest in the contents of the object, which generally is much faster to obtain.    pub fn header(&self) -> Result<gix_odb::find::Header, find::existing::Error> {        self.repo.find_header(self.inner)    }     /// Try to find the [`Object`] associated with this object id, and return `None` if it's not available locally.    ///    /// # Note    ///    /// There can only be one `ObjectRef` per `Easy`. To increase that limit, clone the `Easy`.    pub fn try_object(&self) -> Result<Option<Object<'repo>>, find::Error> {        self.repo.try_find_object(self.inner)    }     /// Find the [`header`][gix_odb::find::Header] associated with this object id, or return `None` if it doesn't exist.    ///    /// Use this method if there is no interest in the contents of the object, which generally is much faster to obtain.    pub fn try_header(&self) -> Result<Option<gix_odb::find::Header>, find::Error> {        self.repo.try_find_header(self.inner)    }     /// Turn this object id into a shortened id with a length in hex as configured by `core.abbrev`.    pub fn shorten(&self) -> Result<gix_hash::Prefix, shorten::Error> {        let hex_len = self.repo.config.hex_len.map_or_else(            || self.repo.objects.packed_object_count().map(calculate_auto_hex_len),            Ok,        )?;         let prefix = gix_odb::store::prefix::disambiguate::Candidate::new(self.inner, hex_len)            .expect("BUG: internal hex-len must always be valid");        self.repo            .objects            .disambiguate_prefix(prefix)?            .ok_or(shorten::Error::NotFound { oid: self.inner })    }     /// Turn this object id into a shortened id with a length in hex as configured by `core.abbrev`, or default    /// to a prefix which equals our id in the unlikely error case.    pub fn shorten_or_id(&self) -> gix_hash::Prefix {        self.shorten().unwrap_or_else(|_| self.inner.into())    }} fn calculate_auto_hex_len(num_packed_objects: u64) -> usize {    let mut len = 64 - num_packed_objects.leading_zeros();    len = len.div_ceil(2);    len.max(7) as usize} ///pub mod shorten {    /// Returned by [`Id::prefix()`][super::Id::shorten()].    #[derive(Debug, thiserror::Error)]    #[expect(missing_docs)]    pub enum Error {        #[error(transparent)]        PackedObjectsCount(#[from] gix_odb::store::load_index::Error),        #[error(transparent)]        DisambiguatePrefix(#[from] gix_odb::store::prefix::disambiguate::Error),        #[error("Id could not be shortened as the object with id {} could not be found", .oid)]        NotFound { oid: gix_hash::ObjectId },    }} impl Deref for Id<'_> {    type Target = oid;     fn deref(&self) -> &Self::Target {        &self.inner    }} impl<'repo> Id<'repo> {    pub(crate) fn from_id(id: impl Into<ObjectId>, repo: &'repo crate::Repository) -> Self {        Id { inner: id.into(), repo }    }     /// Turn this instance into its bare [`ObjectId`].    pub fn detach(self) -> ObjectId {        self.inner    }} impl<'repo> Id<'repo> {    /// Obtain a platform for traversing ancestors of this commit.    pub fn ancestors(&self) -> crate::revision::walk::Platform<'repo> {        crate::revision::walk::Platform::new(Some(self.inner), self.repo)    }} mod impls {    use std::{cmp::Ordering, hash::Hasher};     use gix_hash::{ObjectId, oid};     use crate::{Id, Object, ObjectDetached};     // Eq, Hash, Ord, PartialOrd,     impl std::hash::Hash for Id<'_> {        fn hash<H: Hasher>(&self, state: &mut H) {            self.inner.hash(state);        }    }     impl<'a> PartialOrd<Id<'a>> for Id<'a> {        fn partial_cmp(&self, other: &Id<'a>) -> Option<Ordering> {            self.inner.partial_cmp(&other.inner)        }    }     impl<'repo> PartialEq<Id<'repo>> for Id<'repo> {        fn eq(&self, other: &Id<'repo>) -> bool {            self.inner == other.inner        }    }     impl PartialEq<ObjectId> for Id<'_> {        fn eq(&self, other: &ObjectId) -> bool {            &self.inner == other        }    }     impl<'repo> PartialEq<Id<'repo>> for ObjectId {        fn eq(&self, other: &Id<'repo>) -> bool {            self == &other.inner        }    }     impl PartialEq<oid> for Id<'_> {        fn eq(&self, other: &oid) -> bool {            self.inner == other        }    }     impl<'repo> PartialEq<Object<'repo>> for Id<'repo> {        fn eq(&self, other: &Object<'repo>) -> bool {            self.inner == other.id        }    }     impl PartialEq<ObjectDetached> for Id<'_> {        fn eq(&self, other: &ObjectDetached) -> bool {            self.inner == other.id        }    }     impl std::fmt::Debug for Id<'_> {        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {            self.inner.fmt(f)        }    }     impl std::fmt::Display for Id<'_> {        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {            self.inner.fmt(f)        }    }     impl AsRef<oid> for Id<'_> {        fn as_ref(&self) -> &oid {            &self.inner        }    }     impl<'repo> From<Id<'repo>> for ObjectId {        fn from(v: Id<'repo>) -> Self {            v.inner        }    }} #[cfg(test)]mod tests {    use super::*;     #[test]    fn size_of_oid() {        let actual = std::mem::size_of::<Id<'_>>();        let sha1 = 32;        let sha256_extra = 16;        let ceiling = sha1 + sha256_extra;        assert!(            actual <= ceiling,            "size of oid shouldn't change without notice: {actual} <= {ceiling}"        );    }}