summaryrefslogtreecommitdiffstats
path: root/vendor/gix-revwalk/src/graph/commit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-revwalk/src/graph/commit.rs')
-rw-r--r--vendor/gix-revwalk/src/graph/commit.rs149
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),
+ }
+}