| //! |
| #![allow(clippy::empty_docs)] |
| use std::ops::Deref; |
| |
| use gix_hash::{oid, ObjectId}; |
| |
| use crate::{object::find, Id, Object}; |
| |
| /// 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 + 1) / 2; |
| len.max(7) as usize |
| } |
| |
| /// |
| #[allow(clippy::empty_docs)] |
| pub mod shorten { |
| /// Returned by [`Id::prefix()`][super::Id::shorten()]. |
| #[derive(Debug, thiserror::Error)] |
| #[allow(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<'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. |
| 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::{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> std::fmt::Display 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() { |
| let actual = std::mem::size_of::<Id<'_>>(); |
| let ceiling = 32; |
| assert!( |
| actual <= ceiling, |
| "size of oid shouldn't change without notice: {actual} <= {ceiling}" |
| ) |
| } |
| } |