diff options
Diffstat (limited to 'vendor/gix-revwalk/src/graph/commit.rs')
-rw-r--r-- | vendor/gix-revwalk/src/graph/commit.rs | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/vendor/gix-revwalk/src/graph/commit.rs b/vendor/gix-revwalk/src/graph/commit.rs new file mode 100644 index 000000000..e11a28e36 --- /dev/null +++ b/vendor/gix-revwalk/src/graph/commit.rs @@ -0,0 +1,149 @@ +use smallvec::SmallVec; + +use super::LazyCommit; +use crate::graph::{Commit, CommitterTimestamp, Either, Generation}; + +impl<'graph> LazyCommit<'graph> { + /// Return an iterator over the parents of this commit. + pub fn iter_parents(&self) -> Parents<'graph> { + let backing = match &self.backing { + Either::Left(buf) => Either::Left(gix_object::CommitRefIter::from_bytes(buf)), + Either::Right((cache, pos)) => Either::Right((*cache, cache.commit_at(*pos).iter_parents())), + }; + Parents { backing } + } + + /// Returns the timestamp at which this commit was created. + /// + /// This is the single-most important date for determining recency of commits. + /// Note that this can only fail if the commit is backed by the object database *and* parsing fails. + pub fn committer_timestamp(&self) -> Result<CommitterTimestamp, gix_object::decode::Error> { + Ok(match &self.backing { + Either::Left(buf) => { + gix_object::CommitRefIter::from_bytes(buf) + .committer()? + .time + .seconds_since_unix_epoch as CommitterTimestamp + } + Either::Right((cache, pos)) => cache.commit_at(*pos).committer_timestamp(), + }) + } + + /// Returns the generation of the commit if it is backed by a commit graph. + pub fn generation(&self) -> Option<Generation> { + match &self.backing { + Either::Left(_) => None, + Either::Right((cache, pos)) => cache.commit_at(*pos).generation().into(), + } + } + + /// Convert ourselves into an owned version, which effectively detaches us from the underlying graph. + /// Use `new_data()` to provide the `data` field for the owned `Commit`. + pub fn to_owned<T>(&self, new_data: impl FnOnce() -> T) -> Result<Commit<T>, to_owned::Error> { + let data = new_data(); + Ok(match &self.backing { + Either::Left(buf) => { + use gix_object::commit::ref_iter::Token; + let iter = gix_object::CommitRefIter::from_bytes(buf); + let mut parents = SmallVec::default(); + let mut timestamp = None; + for token in iter { + match token? { + Token::Tree { .. } => {} + Token::Parent { id } => parents.push(id), + Token::Author { .. } => {} + Token::Committer { signature } => { + timestamp = Some(signature.time.seconds_since_unix_epoch as CommitterTimestamp); + break; + } + _ => { + unreachable!( + "we break naturally after seeing the committer which is always at the same spot" + ) + } + } + } + Commit { + parents, + commit_time: timestamp.unwrap_or_default(), + generation: None, + data, + } + } + Either::Right((cache, pos)) => { + let mut parents = SmallVec::default(); + let commit = cache.commit_at(*pos); + for pos in commit.iter_parents() { + let pos = pos?; + parents.push(cache.commit_at(pos).id().to_owned()); + } + Commit { + parents, + commit_time: commit.committer_timestamp(), + generation: Some(commit.generation()), + data, + } + } + }) + } +} + +/// An iterator over the parents of a commit. +pub struct Parents<'graph> { + backing: Either< + gix_object::CommitRefIter<'graph>, + ( + &'graph gix_commitgraph::Graph, + gix_commitgraph::file::commit::Parents<'graph>, + ), + >, +} + +impl<'graph> Iterator for Parents<'graph> { + type Item = Result<gix_hash::ObjectId, iter_parents::Error>; + + fn next(&mut self) -> Option<Self::Item> { + match &mut self.backing { + Either::Left(it) => { + for token in it { + match token { + Ok(gix_object::commit::ref_iter::Token::Tree { .. }) => continue, + Ok(gix_object::commit::ref_iter::Token::Parent { id }) => return Some(Ok(id)), + Ok(_unused_token) => break, + Err(err) => return Some(Err(err.into())), + } + } + None + } + Either::Right((cache, it)) => it + .next() + .map(|r| r.map(|pos| cache.id_at(pos).to_owned()).map_err(Into::into)), + } + } +} + +/// +pub mod iter_parents { + /// The error returned by the [`Parents`][super::Parents] iterator. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error("An error occurred when parsing commit parents")] + DecodeCommit(#[from] gix_object::decode::Error), + #[error("An error occurred when parsing parents from the commit graph")] + DecodeCommitGraph(#[from] gix_commitgraph::file::commit::Error), + } +} + +/// +pub mod to_owned { + /// The error returned by [`to_owned()`][crate::graph::LazyCommit::to_owned()]. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error("A commit could not be decoded during traversal")] + Decode(#[from] gix_object::decode::Error), + #[error("Could not find commit position in graph when traversing parents")] + CommitGraphParent(#[from] gix_commitgraph::file::commit::Error), + } +} |