310 lines · 11.2 KB · Rust
RawDownload
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/44265pub 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::{BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter, find};     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() })        }         /// 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 find_blob<'a>(            &self,            id: &gix_hash::oid,            buffer: &'a mut Vec<u8>,        ) -> Result<BlobRef<'a>, find::existing_object::Error> {            if id == gix_hash::ObjectId::empty_blob(id.kind()) {                return Ok(BlobRef { data: &[] });            }            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 {                    ObjectRef::Blob(o) => Ok(o),                    o => Err(find::existing_object::Error::ObjectKind {                        oid: id.as_ref().to_owned(),                        actual: o.kind(),                        expected: Kind::Blob,                    }),                })        }         /// 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 find_tree<'a>(            &self,            id: &gix_hash::oid,            buffer: &'a mut Vec<u8>,        ) -> Result<TreeRef<'a>, find::existing_object::Error> {            if id == gix_hash::ObjectId::empty_tree(id.kind()) {                return Ok(TreeRef { entries: Vec::new() });            }            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 {                    ObjectRef::Tree(o) => Ok(o),                    o => Err(find::existing_object::Error::ObjectKind {                        oid: id.as_ref().to_owned(),                        actual: o.kind(),                        expected: Kind::Tree,                    }),                })        }         make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>);        make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'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};