1#![allow(clippy::empty_docs)]
3use std::ops::Deref;
4
5use gix_hash::{oid, ObjectId};
6
7use crate::{object::find, Id, Object};
8
9impl<'repo> Id<'repo> {
11 pub fn object(&self) -> Result<Object<'repo>, find::existing::Error> {
17 self.repo.find_object(self.inner)
18 }
19
20 pub fn header(&self) -> Result<gix_odb::find::Header, find::existing::Error> {
24 self.repo.find_header(self.inner)
25 }
26
27 pub fn try_object(&self) -> Result<Option<Object<'repo>>, find::Error> {
33 self.repo.try_find_object(self.inner)
34 }
35
36 pub fn try_header(&self) -> Result<Option<gix_odb::find::Header>, find::Error> {
40 self.repo.try_find_header(self.inner)
41 }
42
43 pub fn shorten(&self) -> Result<gix_hash::Prefix, shorten::Error> {
45 let hex_len = self.repo.config.hex_len.map_or_else(
46 || self.repo.objects.packed_object_count().map(calculate_auto_hex_len),
47 Ok,
48 )?;
49
50 let prefix = gix_odb::store::prefix::disambiguate::Candidate::new(self.inner, hex_len)
51 .expect("BUG: internal hex-len must always be valid");
52 self.repo
53 .objects
54 .disambiguate_prefix(prefix)?
55 .ok_or(shorten::Error::NotFound { oid: self.inner })
56 }
57
58 pub fn shorten_or_id(&self) -> gix_hash::Prefix {
61 self.shorten().unwrap_or_else(|_| self.inner.into())
62 }
63}
64
65fn calculate_auto_hex_len(num_packed_objects: u64) -> usize {
66 let mut len = 64 - num_packed_objects.leading_zeros();
67 len = len.div_ceil(2);
68 len.max(7) as usize
69}
70
71pub mod shorten {
73 #[derive(Debug, thiserror::Error)]
75 #[allow(missing_docs)]
76 pub enum Error {
77 #[error(transparent)]
78 PackedObjectsCount(#[from] gix_odb::store::load_index::Error),
79 #[error(transparent)]
80 DisambiguatePrefix(#[from] gix_odb::store::prefix::disambiguate::Error),
81 #[error("Id could not be shortened as the object with id {} could not be found", .oid)]
82 NotFound { oid: gix_hash::ObjectId },
83 }
84}
85
86impl Deref for Id<'_> {
87 type Target = oid;
88
89 fn deref(&self) -> &Self::Target {
90 &self.inner
91 }
92}
93
94impl<'repo> Id<'repo> {
95 pub(crate) fn from_id(id: impl Into<ObjectId>, repo: &'repo crate::Repository) -> Self {
96 Id { inner: id.into(), repo }
97 }
98
99 pub fn detach(self) -> ObjectId {
101 self.inner
102 }
103}
104
105impl<'repo> Id<'repo> {
106 pub fn ancestors(&self) -> crate::revision::walk::Platform<'repo> {
108 crate::revision::walk::Platform::new(Some(self.inner), self.repo)
109 }
110}
111
112mod impls {
113 use std::{cmp::Ordering, hash::Hasher};
114
115 use gix_hash::{oid, ObjectId};
116
117 use crate::{Id, Object, ObjectDetached};
118
119 impl std::hash::Hash for Id<'_> {
122 fn hash<H: Hasher>(&self, state: &mut H) {
123 self.inner.hash(state);
124 }
125 }
126
127 impl<'a> PartialOrd<Id<'a>> for Id<'a> {
128 fn partial_cmp(&self, other: &Id<'a>) -> Option<Ordering> {
129 self.inner.partial_cmp(&other.inner)
130 }
131 }
132
133 impl<'repo> PartialEq<Id<'repo>> for Id<'repo> {
134 fn eq(&self, other: &Id<'repo>) -> bool {
135 self.inner == other.inner
136 }
137 }
138
139 impl PartialEq<ObjectId> for Id<'_> {
140 fn eq(&self, other: &ObjectId) -> bool {
141 &self.inner == other
142 }
143 }
144
145 impl<'repo> PartialEq<Id<'repo>> for ObjectId {
146 fn eq(&self, other: &Id<'repo>) -> bool {
147 self == &other.inner
148 }
149 }
150
151 impl PartialEq<oid> for Id<'_> {
152 fn eq(&self, other: &oid) -> bool {
153 self.inner == other
154 }
155 }
156
157 impl<'repo> PartialEq<Object<'repo>> for Id<'repo> {
158 fn eq(&self, other: &Object<'repo>) -> bool {
159 self.inner == other.id
160 }
161 }
162
163 impl PartialEq<ObjectDetached> for Id<'_> {
164 fn eq(&self, other: &ObjectDetached) -> bool {
165 self.inner == other.id
166 }
167 }
168
169 impl std::fmt::Debug for Id<'_> {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 self.inner.fmt(f)
172 }
173 }
174
175 impl std::fmt::Display for Id<'_> {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 self.inner.fmt(f)
178 }
179 }
180
181 impl AsRef<oid> for Id<'_> {
182 fn as_ref(&self) -> &oid {
183 &self.inner
184 }
185 }
186
187 impl<'repo> From<Id<'repo>> for ObjectId {
188 fn from(v: Id<'repo>) -> Self {
189 v.inner
190 }
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197
198 #[test]
199 fn size_of_oid() {
200 let actual = std::mem::size_of::<Id<'_>>();
201 let ceiling = 32;
202 assert!(
203 actual <= ceiling,
204 "size of oid shouldn't change without notice: {actual} <= {ceiling}"
205 );
206 }
207}