Sebastian Thielrefactor40b86a75 years agoHistory
95 lines · 3.2 KB · Rust
RawDownload
//! Various iterators to traverse a graph ///pub mod ancestors {    use crate::pack;    use git_hash::ObjectId;    use git_object::immutable;    use std::{        borrow::Borrow,        collections::{BTreeSet, VecDeque},    };     /// The error used in the iterator implementation of [Ancestors].    #[derive(Debug, thiserror::Error)]    #[allow(missing_docs)]    pub enum Error<LocateErr>    where        LocateErr: std::error::Error + 'static,    {        #[error(transparent)]        Locate(LocateErr),        #[error(transparent)]        ObjectDecode(#[from] immutable::object::decode::Error),        #[error("Object id {oid} wasn't found in object database")]        NotFound { oid: ObjectId },    }     /// An iterator over the ancestors one or more starting commits    pub struct Ancestors<'a, Cache, Locate> {        db: Locate,        next: VecDeque<ObjectId>,        buf: Vec<u8>,        seen: BTreeSet<ObjectId>,        cache: &'a mut Cache,    }     impl<'a, Cache, Locate> Ancestors<'a, Cache, Locate>    where        Cache: pack::cache::DecodeEntry,        Locate: crate::Locate,    {        /// Create a new instance.        ///        /// * `db` - a way to lookup new object data during traversal        /// * `tips`        ///   * the starting points of the iteration, usually commits        ///   * each commit they lead to will only be returned once, including the tip that started it        /// * `cache` - a way to speedup object database access        pub fn new(db: Locate, tips: impl IntoIterator<Item = impl Into<ObjectId>>, cache: &'a mut Cache) -> Self {            let next: VecDeque<_> = tips.into_iter().map(Into::into).collect();            let seen = next.iter().cloned().collect();            Ancestors {                db,                next,                buf: Vec::with_capacity(4096),                seen,                cache,            }        }    }     impl<'a, Cache, Locate> Iterator for Ancestors<'a, Cache, Locate>    where        Cache: pack::cache::DecodeEntry,        Locate: crate::Locate,    {        type Item = Result<ObjectId, Error<Locate::Error>>;         fn next(&mut self) -> Option<Self::Item> {            let res = self.next.pop_front();            if let Some(oid) = res {                match self.db.borrow().locate(oid, &mut self.buf, self.cache) {                    Ok(Some(obj)) => match obj.decode().map_err(Error::from) {                        Ok(obj) => {                            if let Some(commit) = obj.as_commit() {                                for parent_id in commit.parents() {                                    let was_inserted = self.seen.insert(parent_id);                                    if was_inserted {                                        self.next.push_back(parent_id);                                    }                                }                            }                        }                        Err(err) => return Some(Err(err)),                    },                    Ok(None) => return Some(Err(Error::NotFound { oid })),                    Err(err) => return Some(Err(Error::Locate(err))),                }            }            res.map(Ok)        }    }}#[doc(inline)]pub use ancestors::Ancestors;