186 lines · 5.3 KB · Rust
RawDownload
//!use std::ops::Deref; use git_hash::{oid, ObjectId}; use crate::{object::find, revision, Id, Object}; /// An [object id][ObjectId] infused with `Easy`.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)    }     /// 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)    }     /// Turn this object id into a shortened id with a length in hex as configured by `core.abbrev`.    pub fn shorten(&self) -> Result<git_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,            )            .map_err(shorten::Error::Find)?;         let prefix = git_odb::find::PotentialPrefix::new(self.inner, hex_len)            .expect("BUG: internal hex-len must always be valid");        self.repo            .objects            .disambiguate_prefix(prefix)            .map_err(find::existing::Error::Find)?            .ok_or(find::existing::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) -> git_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 + 1) / 2;    len.max(7) as usize} ///pub mod shorten {    /// Returned by [`Id::prefix()`][super::Id::shorten()].    pub type Error = crate::object::find::existing::Error;} impl<'repo> Deref for Id<'repo> {    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.    ///    /// Note that unless [`error_on_missing_commit()`][revision::Walk::error_on_missing_commit()] is enabled, which be default it is not,    /// one will always see an empty iteration even if this id is not a commit, instead of an error.    /// If this is undesirable, it's best to check for the correct object type before creating an iterator.    pub fn ancestors(&self) -> revision::walk::Platform<'repo> {        revision::walk::Platform::new(Some(self.inner), self.repo)    }} mod impls {    use std::{cmp::Ordering, hash::Hasher};     use git_hash::{oid, ObjectId};     use crate::{Id, Object, ObjectDetached};     // Eq, Hash, Ord, PartialOrd,     impl<'a> std::hash::Hash for Id<'a> {        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<'repo> PartialEq<ObjectId> for Id<'repo> {        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<'repo> PartialEq<oid> for Id<'repo> {        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<'repo> PartialEq<ObjectDetached> for Id<'repo> {        fn eq(&self, other: &ObjectDetached) -> bool {            self.inner == other.id        }    }     impl<'repo> std::fmt::Debug for Id<'repo> {        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {            self.inner.fmt(f)        }    }     impl<'repo> AsRef<oid> for Id<'repo> {        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() {        assert_eq!(            std::mem::size_of::<Id<'_>>(),            32,            "size of oid shouldn't change without notice"        )    }}