History

feat: Add `Repository::has_object()` as a high-level alternative.

Previously, one would have to call `repo.objects.contains()`, which is fine, but this method is necessary for symmetry of the API and one shouldn't have to drop down a level to do this. This method also knows empty trees as special case.

Sebastian Thiel committed 3 years ago

Commit 787a9aa1 parent 3cec9352 files · +28 −7Browse files

Unified · Split

2 files
  1. gix/src/repository/object.rs +26 −7
  2. gix/tests/repository/object.rs +2 −0
gix/src/repository/object.rs+26−7
@@ -26,7 +26,7 @@ impl crate::Repository { · 25 unmodified lines
26 #[momo]26 #[momo]
27 pub fn find_object(&self, id: impl Into<ObjectId>) -> Result<Object<'_>, object::find::existing::Error> {27 pub fn find_object(&self, id: impl Into<ObjectId>) -> Result<Object<'_>, object::find::existing::Error> {
28 let id = id.into();28 let id = id.into();
29 if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {29 if id == ObjectId::empty_tree(self.object_hash()) {
30 return Ok(Object {30 return Ok(Object {
31 id,31 id,
32 kind: gix_object::Kind::Tree,32 kind: gix_object::Kind::Tree,
@@ -46,7 +46,7 @@ impl crate::Repository { · 13 unmodified lines
46 #[momo]46 #[momo]
47 pub fn find_header(&self, id: impl Into<ObjectId>) -> Result<gix_odb::find::Header, object::find::existing::Error> {47 pub fn find_header(&self, id: impl Into<ObjectId>) -> Result<gix_odb::find::Header, object::find::existing::Error> {
48 let id = id.into();48 let id = id.into();
49 if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {49 if id == ObjectId::empty_tree(self.object_hash()) {
50 return Ok(gix_odb::find::Header::Loose {50 return Ok(gix_odb::find::Header::Loose {
51 kind: gix_object::Kind::Tree,51 kind: gix_object::Kind::Tree,
52 size: 0,52 size: 0,
@@ -55,6 +55,25 @@ impl crate::Repository { · 2 unmodified lines
55 self.objects.header(id)55 self.objects.header(id)
56 }56 }
57 57
58 /// Return `true` if `id` exists in the object database.
59 ///
60 /// # Performance
61 ///
62 /// This method can be slow if the underlying [object database](crate::Repository::objects) has
63 /// an unsuitable [RefreshMode](gix_odb::store::RefreshMode) and `id` is not likely to exist.
64 /// Use [`repo.objects.refresh_never()`](gix_odb::store::Handle::refresh_never) to avoid expensive
65 /// IO-bound refreshes if an object wasn't found.
66 #[doc(alias = "exists", alias = "git2")]
67 #[momo]
68 pub fn has_object(&self, id: impl AsRef<gix_hash::oid>) -> bool {
69 let id = id.as_ref();
70 if id == ObjectId::empty_tree(self.object_hash()) {
71 true
72 } else {
73 self.objects.contains(id)
74 }
75 }
76
58 /// Obtain information about an object without fully decoding it, or `None` if the object doesn't exist.77 /// Obtain information about an object without fully decoding it, or `None` if the object doesn't exist.
59 ///78 ///
60 /// Note that despite being cheaper than [`Self::try_find_object()`], there is still some effort traversing delta-chains.79 /// Note that despite being cheaper than [`Self::try_find_object()`], there is still some effort traversing delta-chains.
@@ -64,7 +83,7 @@ impl crate::Repository { · 3 unmodified lines
64 id: impl Into<ObjectId>,83 id: impl Into<ObjectId>,
65 ) -> Result<Option<gix_odb::find::Header>, object::find::Error> {84 ) -> Result<Option<gix_odb::find::Header>, object::find::Error> {
66 let id = id.into();85 let id = id.into();
67 if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {86 if id == ObjectId::empty_tree(self.object_hash()) {
68 return Ok(Some(gix_odb::find::Header::Loose {87 return Ok(Some(gix_odb::find::Header::Loose {
69 kind: gix_object::Kind::Tree,88 kind: gix_object::Kind::Tree,
70 size: 0,89 size: 0,
@@ -77,7 +96,7 @@ impl crate::Repository { · 6 unmodified lines
77 #[momo]96 #[momo]
78 pub fn try_find_object(&self, id: impl Into<ObjectId>) -> Result<Option<Object<'_>>, object::find::Error> {97 pub fn try_find_object(&self, id: impl Into<ObjectId>) -> Result<Option<Object<'_>>, object::find::Error> {
79 let id = id.into();98 let id = id.into();
80 if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {99 if id == ObjectId::empty_tree(self.object_hash()) {
81 return Ok(Some(Object {100 return Ok(Some(Object {
82 id,101 id,
83 kind: gix_object::Kind::Tree,102 kind: gix_object::Kind::Tree,
@@ -236,7 +255,7 @@ impl crate::Repository { · 152 unmodified lines
236 reference: FullName,255 reference: FullName,
237 message: &str,256 message: &str,
238 tree: ObjectId,257 tree: ObjectId,
239 parents: SmallVec<[gix_hash::ObjectId; 1]>,258 parents: SmallVec<[ObjectId; 1]>,
240 ) -> Result<Id<'_>, commit::Error> {259 ) -> Result<Id<'_>, commit::Error> {
241 use gix_ref::{260 use gix_ref::{
242 transaction::{Change, RefEdit},261 transaction::{Change, RefEdit},
@@ -310,12 +329,12 @@ impl crate::Repository { · 67 unmodified lines
310 self.commit_as(committer, author, reference, message, tree, parents)329 self.commit_as(committer, author, reference, message, tree, parents)
311 }330 }
312 331
313 /// Return an empty tree object, suitable for [getting changes](crate::Tree::changes()).332 /// Return an empty tree object, suitable for [getting changes](Tree::changes()).
314 ///333 ///
315 /// Note that the returned object is special and doesn't necessarily physically exist in the object database.334 /// Note that the returned object is special and doesn't necessarily physically exist in the object database.
316 /// This means that this object can be used in an uninitialized, empty repository which would report to have no objects at all.335 /// This means that this object can be used in an uninitialized, empty repository which would report to have no objects at all.
317 pub fn empty_tree(&self) -> Tree<'_> {336 pub fn empty_tree(&self) -> Tree<'_> {
318 self.find_object(gix_hash::ObjectId::empty_tree(self.object_hash()))337 self.find_object(ObjectId::empty_tree(self.object_hash()))
319 .expect("always present")338 .expect("always present")
320 .into_tree()339 .into_tree()
321 }340 }
gix/tests/repository/object.rs+2−0
@@ -68,6 +68,7 @@ fn writes_avoid_io_using_duplicate_check() -> crate::Result { · 67 unmodified lines
68 68
69 for id in repo.objects.iter()? {69 for id in repo.objects.iter()? {
70 let id = id?;70 let id = id?;
71 assert!(repo.has_object(id));
71 let obj = repo.find_object(id)?;72 let obj = repo.find_object(id)?;
72 let header = repo.find_header(id)?;73 let header = repo.find_header(id)?;
73 assert_eq!(obj.kind, header.kind(), "header and object agree");74 assert_eq!(obj.kind, header.kind(), "header and object agree");
@@ -156,6 +157,7 @@ mod find { · 82 unmodified lines
156 let repo = basic_repo()?;157 let repo = basic_repo()?;
157 let empty_tree = gix::hash::ObjectId::empty_tree(repo.object_hash());158 let empty_tree = gix::hash::ObjectId::empty_tree(repo.object_hash());
158 assert_eq!(repo.find_object(empty_tree)?.into_tree().iter().count(), 0);159 assert_eq!(repo.find_object(empty_tree)?.into_tree().iter().count(), 0);
160 assert!(repo.has_object(empty_tree));
159 assert_eq!(161 assert_eq!(
160 repo.find_header(empty_tree)?,162 repo.find_header(empty_tree)?,
161 gix_odb::find::Header::Loose {163 gix_odb::find::Header::Loose {