Skip to content

Commit

Permalink
feat: Add Repository::has_object() as a high-level alternative.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Byron committed Oct 12, 2023
1 parent 3cec935 commit 787a9aa
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
33 changes: 26 additions & 7 deletions gix/src/repository/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl crate::Repository {
#[momo]
pub fn find_object(&self, id: impl Into<ObjectId>) -> Result<Object<'_>, object::find::existing::Error> {
let id = id.into();
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
if id == ObjectId::empty_tree(self.object_hash()) {
return Ok(Object {
id,
kind: gix_object::Kind::Tree,
Expand All @@ -46,7 +46,7 @@ impl crate::Repository {
#[momo]
pub fn find_header(&self, id: impl Into<ObjectId>) -> Result<gix_odb::find::Header, object::find::existing::Error> {
let id = id.into();
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
if id == ObjectId::empty_tree(self.object_hash()) {
return Ok(gix_odb::find::Header::Loose {
kind: gix_object::Kind::Tree,
size: 0,
Expand All @@ -55,6 +55,25 @@ impl crate::Repository {
self.objects.header(id)
}

/// Return `true` if `id` exists in the object database.
///
/// # Performance
///
/// This method can be slow if the underlying [object database](crate::Repository::objects) has
/// an unsuitable [RefreshMode](gix_odb::store::RefreshMode) and `id` is not likely to exist.
/// Use [`repo.objects.refresh_never()`](gix_odb::store::Handle::refresh_never) to avoid expensive
/// IO-bound refreshes if an object wasn't found.
#[doc(alias = "exists", alias = "git2")]
#[momo]
pub fn has_object(&self, id: impl AsRef<gix_hash::oid>) -> bool {
let id = id.as_ref();
if id == ObjectId::empty_tree(self.object_hash()) {
true
} else {
self.objects.contains(id)
}
}

/// Obtain information about an object without fully decoding it, or `None` if the object doesn't exist.
///
/// Note that despite being cheaper than [`Self::try_find_object()`], there is still some effort traversing delta-chains.
Expand All @@ -64,7 +83,7 @@ impl crate::Repository {
id: impl Into<ObjectId>,
) -> Result<Option<gix_odb::find::Header>, object::find::Error> {
let id = id.into();
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
if id == ObjectId::empty_tree(self.object_hash()) {
return Ok(Some(gix_odb::find::Header::Loose {
kind: gix_object::Kind::Tree,
size: 0,
Expand All @@ -77,7 +96,7 @@ impl crate::Repository {
#[momo]
pub fn try_find_object(&self, id: impl Into<ObjectId>) -> Result<Option<Object<'_>>, object::find::Error> {
let id = id.into();
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
if id == ObjectId::empty_tree(self.object_hash()) {
return Ok(Some(Object {
id,
kind: gix_object::Kind::Tree,
Expand Down Expand Up @@ -236,7 +255,7 @@ impl crate::Repository {
reference: FullName,
message: &str,
tree: ObjectId,
parents: SmallVec<[gix_hash::ObjectId; 1]>,
parents: SmallVec<[ObjectId; 1]>,
) -> Result<Id<'_>, commit::Error> {
use gix_ref::{
transaction::{Change, RefEdit},
Expand Down Expand Up @@ -310,12 +329,12 @@ impl crate::Repository {
self.commit_as(committer, author, reference, message, tree, parents)
}

/// Return an empty tree object, suitable for [getting changes](crate::Tree::changes()).
/// Return an empty tree object, suitable for [getting changes](Tree::changes()).
///
/// Note that the returned object is special and doesn't necessarily physically exist in the object database.
/// This means that this object can be used in an uninitialized, empty repository which would report to have no objects at all.
pub fn empty_tree(&self) -> Tree<'_> {
self.find_object(gix_hash::ObjectId::empty_tree(self.object_hash()))
self.find_object(ObjectId::empty_tree(self.object_hash()))
.expect("always present")
.into_tree()
}
Expand Down
2 changes: 2 additions & 0 deletions gix/tests/repository/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ fn writes_avoid_io_using_duplicate_check() -> crate::Result {

for id in repo.objects.iter()? {
let id = id?;
assert!(repo.has_object(id));
let obj = repo.find_object(id)?;
let header = repo.find_header(id)?;
assert_eq!(obj.kind, header.kind(), "header and object agree");
Expand Down Expand Up @@ -156,6 +157,7 @@ mod find {
let repo = basic_repo()?;
let empty_tree = gix::hash::ObjectId::empty_tree(repo.object_hash());
assert_eq!(repo.find_object(empty_tree)?.into_tree().iter().count(), 0);
assert!(repo.has_object(empty_tree));
assert_eq!(
repo.find_header(empty_tree)?,
gix_odb::find::Header::Loose {
Expand Down

0 comments on commit 787a9aa

Please sign in to comment.