use crate::{data, find};
use gix_error::Result;
pub trait Find {
fn contains(&self, id: &gix_hash::oid) -> bool;
fn try_find<'a>(
&self,
id: &gix_hash::oid,
buffer: &'a mut Vec<u8>,
) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
self.try_find_cached(id, buffer, &mut crate::cache::Never)
}
fn try_find_cached<'a>(
&self,
id: &gix_hash::oid,
buffer: &'a mut Vec<u8>,
pack_cache: &mut dyn crate::cache::DecodeEntry,
) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>>;
fn location_by_oid(&self, id: &gix_hash::oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>>;
fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>>;
fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry>;
}
mod ext {
use gix_error::{Error, Result};
use gix_error::{ResultExt, message};
use gix_object::{BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter};
fn not_found(id: &gix_hash::oid) -> Error {
message!("An object with id {id} could not be found").not_found_error()
}
fn wrong_kind(id: &gix_hash::oid, actual: Kind, expected: Kind) -> Error {
message!("Expected object of kind {expected} but got {actual} at {id}").validation_error()
}
macro_rules! make_obj_lookup {
($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => {
fn $method<'a>(
&self,
id: &gix_hash::oid,
buffer: &'a mut Vec<u8>,
) -> Result<($object_type, Option<crate::data::entry::Location>)> {
let id = id.as_ref();
self.try_find(id, buffer)?
.ok_or_else(|| not_found(id))
.and_then(|(o, l)| {
o.decode()
.or_raise(|| message!("Could not decode object at {id}").corrupted())
.map(|o| (o, l))
})
.and_then(|(o, l)| match o {
$object_variant(o) => return Ok((o, l)),
o => Err(wrong_kind(id, o.kind(), $object_kind)),
})
}
};
}
macro_rules! make_iter_lookup {
($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => {
fn $method<'a>(
&self,
id: &gix_hash::oid,
buffer: &'a mut Vec<u8>,
) -> Result<($object_type, Option<crate::data::entry::Location>)> {
let id = id.as_ref();
self.try_find(id, buffer)?
.ok_or_else(|| not_found(id))
.and_then(|(o, l)| {
o.$into_iter()
.ok_or_else(|| wrong_kind(id, o.kind, $object_kind))
.map(|i| (i, l))
})
}
};
}
pub trait FindExt: super::Find {
fn find<'a>(
&self,
id: &gix_hash::oid,
buffer: &'a mut Vec<u8>,
) -> Result<(gix_object::Data<'a>, Option<crate::data::entry::Location>)> {
self.try_find(id, buffer)?.ok_or_else(|| not_found(id))
}
make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>);
make_obj_lookup!(find_tree, ObjectRef::Tree, Kind::Tree, TreeRef<'a>);
make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>);
make_obj_lookup!(find_blob, ObjectRef::Blob, Kind::Blob, BlobRef<'a>);
make_iter_lookup!(find_commit_iter, Kind::Blob, CommitRefIter<'a>, try_into_commit_iter);
make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter);
make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter);
}
impl<T: super::Find + ?Sized> FindExt for T {}
}
pub use ext::FindExt;
mod find_impls {
use gix_error::Result;
use std::{ops::Deref, rc::Rc};
use gix_hash::oid;
use crate::{data, find};
impl<T> crate::Find for &T
where
T: crate::Find,
{
fn contains(&self, id: &oid) -> bool {
(*self).contains(id)
}
fn try_find_cached<'a>(
&self,
id: &oid,
buffer: &'a mut Vec<u8>,
pack_cache: &mut dyn crate::cache::DecodeEntry,
) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
(*self).try_find_cached(id, buffer, pack_cache)
}
fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>> {
(*self).location_by_oid(id, buf)
}
fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>> {
(*self).pack_offsets_and_oid(pack_id)
}
fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
(*self).entry_by_location(location)
}
}
impl<T> super::Find for std::sync::Arc<T>
where
T: super::Find,
{
fn contains(&self, id: &oid) -> bool {
self.deref().contains(id)
}
fn try_find_cached<'a>(
&self,
id: &oid,
buffer: &'a mut Vec<u8>,
pack_cache: &mut dyn crate::cache::DecodeEntry,
) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
self.deref().try_find_cached(id, buffer, pack_cache)
}
fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>> {
self.deref().location_by_oid(id, buf)
}
fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>> {
self.deref().pack_offsets_and_oid(pack_id)
}
fn entry_by_location(&self, object: &data::entry::Location) -> Option<find::Entry> {
self.deref().entry_by_location(object)
}
}
impl<T> super::Find for Rc<T>
where
T: super::Find,
{
fn contains(&self, id: &oid) -> bool {
self.deref().contains(id)
}
fn try_find_cached<'a>(
&self,
id: &oid,
buffer: &'a mut Vec<u8>,
pack_cache: &mut dyn crate::cache::DecodeEntry,
) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
self.deref().try_find_cached(id, buffer, pack_cache)
}
fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>> {
self.deref().location_by_oid(id, buf)
}
fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>> {
self.deref().pack_offsets_and_oid(pack_id)
}
fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
self.deref().entry_by_location(location)
}
}
impl<T> super::Find for Box<T>
where
T: super::Find,
{
fn contains(&self, id: &oid) -> bool {
self.deref().contains(id)
}
fn try_find_cached<'a>(
&self,
id: &oid,
buffer: &'a mut Vec<u8>,
pack_cache: &mut dyn crate::cache::DecodeEntry,
) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
self.deref().try_find_cached(id, buffer, pack_cache)
}
fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>> {
self.deref().location_by_oid(id, buf)
}
fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>> {
self.deref().pack_offsets_and_oid(pack_id)
}
fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
self.deref().entry_by_location(location)
}
}
}