use crate::{data, pack};
pub trait Find {
type Error: std::error::Error + 'static;
fn find<'a>(
&self,
id: impl AsRef<git_hash::oid>,
buffer: &'a mut Vec<u8>,
pack_cache: &mut impl crate::pack::cache::DecodeEntry,
) -> Result<Option<data::Object<'a>>, Self::Error>;
fn pack_entry(&self, object: &data::Object<'_>) -> Option<PackEntry<'_>>;
}
mod ext {
use crate::{data, find};
use git_object::{immutable, Kind};
macro_rules! make_obj_lookup {
($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => {
fn $method<'a>(
&self,
id: impl AsRef<git_hash::oid>,
buffer: &'a mut Vec<u8>,
pack_cache: &mut impl crate::pack::cache::DecodeEntry,
) -> Result<$object_type, find::existing_object::Error<Self::Error>> {
let id = id.as_ref();
self.find(id, buffer, pack_cache)
.map_err(find::existing_object::Error::Find)?
.ok_or_else(|| find::existing_object::Error::NotFound {
oid: id.as_ref().to_owned(),
})
.and_then(|o| o.decode().map_err(find::existing_object::Error::Decode))
.and_then(|o| match o {
$object_variant(o) => return Ok(o),
_other => Err(find::existing_object::Error::ObjectKind {
expected: $object_kind,
}),
})
}
};
}
macro_rules! make_iter_lookup {
($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => {
fn $method<'a>(
&self,
id: impl AsRef<git_hash::oid>,
buffer: &'a mut Vec<u8>,
pack_cache: &mut impl crate::pack::cache::DecodeEntry,
) -> Result<$object_type, find::existing_iter::Error<Self::Error>> {
let id = id.as_ref();
self.find(id, buffer, pack_cache)
.map_err(find::existing_iter::Error::Find)?
.ok_or_else(|| find::existing_iter::Error::NotFound {
oid: id.as_ref().to_owned(),
})
.and_then(|o| {
o.$into_iter()
.ok_or_else(|| find::existing_iter::Error::ObjectKind {
expected: $object_kind,
})
})
}
};
}
pub trait FindExt: super::Find {
fn find_existing<'a>(
&self,
id: impl AsRef<git_hash::oid>,
buffer: &'a mut Vec<u8>,
pack_cache: &mut impl crate::pack::cache::DecodeEntry,
) -> Result<data::Object<'a>, find::existing::Error<Self::Error>> {
let id = id.as_ref();
self.find(id, buffer, pack_cache)
.map_err(find::existing::Error::Find)?
.ok_or_else(|| find::existing::Error::NotFound {
oid: id.as_ref().to_owned(),
})
}
make_obj_lookup!(
find_existing_commit,
immutable::Object::Commit,
Kind::Commit,
immutable::Commit<'a>
);
make_obj_lookup!(
find_existing_tree,
immutable::Object::Tree,
Kind::Tree,
immutable::Tree<'a>
);
make_obj_lookup!(find_existing_tag, immutable::Object::Tag, Kind::Tag, immutable::Tag<'a>);
make_obj_lookup!(
find_existing_blob,
immutable::Object::Blob,
Kind::Blob,
immutable::Blob<'a>
);
make_iter_lookup!(
find_existing_commit_iter,
Kind::Blob,
immutable::CommitIter<'a>,
into_commit_iter
);
make_iter_lookup!(
find_existing_tree_iter,
Kind::Tree,
immutable::TreeIter<'a>,
into_tree_iter
);
}
impl<T: super::Find> FindExt for T {}
}
pub use ext::FindExt;
pub mod existing {
use git_hash::ObjectId;
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error<T: std::error::Error + 'static> {
#[error(transparent)]
Find(T),
#[error("An object with id {} could not be found", .oid)]
NotFound { oid: ObjectId },
}
}
pub mod existing_object {
use git_hash::ObjectId;
use git_object::immutable;
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error<T: std::error::Error + 'static> {
#[error(transparent)]
Find(T),
#[error(transparent)]
Decode(immutable::object::decode::Error),
#[error("An object with id {} could not be found", .oid)]
NotFound { oid: ObjectId },
#[error("Expected object of kind {} something else", .expected)]
ObjectKind { expected: git_object::Kind },
}
}
pub mod existing_iter {
use git_hash::ObjectId;
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error<T: std::error::Error + 'static> {
#[error(transparent)]
Find(T),
#[error("An object with id {} could not be found", .oid)]
NotFound { oid: ObjectId },
#[error("Expected object of kind {} something else", .expected)]
ObjectKind { expected: git_object::Kind },
}
}
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub struct PackEntry<'a> {
pub data: &'a [u8],
pub crc32: Option<u32>,
pub version: pack::data::Version,
}
mod find_impls {
use crate::{data, data::Object, find::PackEntry, pack};
use git_hash::oid;
use std::ops::Deref;
impl<T> super::Find for std::sync::Arc<T>
where
T: super::Find,
{
type Error = T::Error;
fn find<'a>(
&self,
id: impl AsRef<oid>,
buffer: &'a mut Vec<u8>,
pack_cache: &mut impl pack::cache::DecodeEntry,
) -> Result<Option<Object<'a>>, Self::Error> {
self.deref().find(id, buffer, pack_cache)
}
fn pack_entry(&self, object: &data::Object<'_>) -> Option<PackEntry<'_>> {
self.deref().pack_entry(object)
}
}
impl<T> super::Find for Box<T>
where
T: super::Find,
{
type Error = T::Error;
fn find<'a>(
&self,
id: impl AsRef<oid>,
buffer: &'a mut Vec<u8>,
pack_cache: &mut impl pack::cache::DecodeEntry,
) -> Result<Option<Object<'a>>, Self::Error> {
self.deref().find(id, buffer, pack_cache)
}
fn pack_entry(&self, object: &data::Object<'_>) -> Option<PackEntry<'_>> {
self.deref().pack_entry(object)
}
}
}