summaryrefslogtreecommitdiffstats
path: root/vendor/gix-object/src/traits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-object/src/traits.rs')
-rw-r--r--vendor/gix-object/src/traits.rs260
1 files changed, 260 insertions, 0 deletions
diff --git a/vendor/gix-object/src/traits.rs b/vendor/gix-object/src/traits.rs
index ce0463c98..b773a5cc8 100644
--- a/vendor/gix-object/src/traits.rs
+++ b/vendor/gix-object/src/traits.rs
@@ -41,3 +41,263 @@ where
<T as WriteTo>::size(self)
}
}
+
+mod find {
+ use crate::find;
+
+ /// Check if an object is present in an object store.
+ pub trait Exists {
+ /// Returns `true` if the object exists in the database.
+ fn exists(&self, id: &gix_hash::oid) -> bool;
+ }
+
+ /// Find an object in the object store.
+ ///
+ /// ## Notes
+ ///
+ /// Find effectively needs [generic associated types][issue] to allow a trait for the returned object type.
+ /// Until then, we will have to make due with explicit types and give them the potentially added features we want.
+ ///
+ /// [issue]: https://github.com/rust-lang/rust/issues/44265
+ pub trait Find {
+ /// Find an object matching `id` in the database while placing its raw, possibly encoded data into `buffer`.
+ ///
+ /// Returns `Some` object if it was present in the database, or the error that occurred during lookup or object
+ /// retrieval.
+ fn try_find<'a>(
+ &self,
+ id: &gix_hash::oid,
+ buffer: &'a mut Vec<u8>,
+ ) -> Result<Option<crate::Data<'a>>, find::Error>;
+ }
+
+ /// Find the header of an object in the object store.
+ pub trait Header {
+ /// Find the header of the object matching `id` in the database.
+ ///
+ /// Returns `Some` header if it was present, or the error that occurred during lookup.
+ fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, find::Error>;
+ }
+
+ /// A combination of [`Find`] and [`Header`] traits to help with `dyn` trait objects.
+ pub trait FindObjectOrHeader: Find + Header {}
+
+ mod _impls {
+ use std::{ops::Deref, rc::Rc, sync::Arc};
+
+ use gix_hash::oid;
+
+ use crate::Data;
+
+ impl<T> crate::Exists for &T
+ where
+ T: crate::Exists,
+ {
+ fn exists(&self, id: &oid) -> bool {
+ (*self).exists(id)
+ }
+ }
+
+ impl<T> crate::FindObjectOrHeader for T where T: crate::Find + crate::FindHeader {}
+
+ impl<T> crate::Find for &T
+ where
+ T: crate::Find,
+ {
+ fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, crate::find::Error> {
+ (*self).try_find(id, buffer)
+ }
+ }
+
+ impl<T> crate::FindHeader for &T
+ where
+ T: crate::FindHeader,
+ {
+ fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, crate::find::Error> {
+ (*self).try_header(id)
+ }
+ }
+
+ impl<T> crate::Exists for Box<T>
+ where
+ T: crate::Exists,
+ {
+ fn exists(&self, id: &oid) -> bool {
+ self.deref().exists(id)
+ }
+ }
+
+ impl<T> crate::Exists for Rc<T>
+ where
+ T: crate::Exists,
+ {
+ fn exists(&self, id: &oid) -> bool {
+ self.deref().exists(id)
+ }
+ }
+
+ impl<T> crate::Find for Rc<T>
+ where
+ T: crate::Find,
+ {
+ fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, crate::find::Error> {
+ self.deref().try_find(id, buffer)
+ }
+ }
+
+ impl<T> crate::FindHeader for Rc<T>
+ where
+ T: crate::FindHeader,
+ {
+ fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, crate::find::Error> {
+ self.deref().try_header(id)
+ }
+ }
+
+ impl<T> crate::Find for Box<T>
+ where
+ T: crate::Find,
+ {
+ fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, crate::find::Error> {
+ self.deref().try_find(id, buffer)
+ }
+ }
+
+ impl<T> crate::FindHeader for Box<T>
+ where
+ T: crate::FindHeader,
+ {
+ fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, crate::find::Error> {
+ self.deref().try_header(id)
+ }
+ }
+
+ impl<T> crate::Exists for Arc<T>
+ where
+ T: crate::Exists,
+ {
+ fn exists(&self, id: &oid) -> bool {
+ self.deref().exists(id)
+ }
+ }
+
+ impl<T> crate::Find for Arc<T>
+ where
+ T: crate::Find,
+ {
+ fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, crate::find::Error> {
+ self.deref().try_find(id, buffer)
+ }
+ }
+
+ impl<T> crate::FindHeader for Arc<T>
+ where
+ T: crate::FindHeader,
+ {
+ fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, crate::find::Error> {
+ self.deref().try_header(id)
+ }
+ }
+ }
+
+ mod ext {
+ use crate::{
+ find, BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter,
+ };
+
+ macro_rules! make_obj_lookup {
+ ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => {
+ /// Like [`find(…)`][Self::find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error
+ /// while returning the desired object type.
+ fn $method<'a>(
+ &self,
+ id: &gix_hash::oid,
+ buffer: &'a mut Vec<u8>,
+ ) -> Result<$object_type, find::existing_object::Error> {
+ self.try_find(id, buffer)
+ .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(|err| find::existing_object::Error::Decode {
+ source: err,
+ oid: id.as_ref().to_owned(),
+ })
+ })
+ .and_then(|o| match o {
+ $object_variant(o) => return Ok(o),
+ o => Err(find::existing_object::Error::ObjectKind {
+ oid: id.as_ref().to_owned(),
+ actual: o.kind(),
+ expected: $object_kind,
+ }),
+ })
+ }
+ };
+ }
+
+ macro_rules! make_iter_lookup {
+ ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => {
+ /// Like [`find(…)`][Self::find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error
+ /// while returning the desired iterator type.
+ fn $method<'a>(
+ &self,
+ id: &gix_hash::oid,
+ buffer: &'a mut Vec<u8>,
+ ) -> Result<$object_type, find::existing_iter::Error> {
+ self.try_find(id, buffer)
+ .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 {
+ oid: id.as_ref().to_owned(),
+ actual: o.kind,
+ expected: $object_kind,
+ })
+ })
+ }
+ };
+ }
+
+ /// An extension trait with convenience functions.
+ pub trait HeaderExt: super::Header {
+ /// Like [`try_header(…)`](super::Header::try_header()), but flattens the `Result<Option<_>>` into a single `Result` making a non-existing header an error.
+ fn header(&self, id: &gix_hash::oid) -> Result<crate::Header, find::existing::Error> {
+ self.try_header(id)
+ .map_err(find::existing::Error::Find)?
+ .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() })
+ }
+ }
+
+ /// An extension trait with convenience functions.
+ pub trait FindExt: super::Find {
+ /// Like [`try_find(…)`](super::Find::try_find()), but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error.
+ fn find<'a>(
+ &self,
+ id: &gix_hash::oid,
+ buffer: &'a mut Vec<u8>,
+ ) -> Result<crate::Data<'a>, find::existing::Error> {
+ self.try_find(id, buffer)
+ .map_err(find::existing::Error::Find)?
+ .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() })
+ }
+
+ 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::Commit, 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, HeaderExt};
+}
+pub use find::*;