git_calver/
repo.rs

1use git2::Commit;
2use git2::Oid;
3use git2::Repository;
4
5pub trait RepositoryExt {
6    fn walk_history<C, T>(&self, commit_id: Oid, callback: C) -> Option<T>
7    where
8        C: Fn(Oid) -> Option<T>;
9
10    fn iter_commit_id<'repo>(&'repo self, commit: &'repo Commit) -> CommitIdIter<'repo>;
11}
12
13impl RepositoryExt for Repository {
14    fn walk_history<C, T>(&self, commit_id: Oid, callback: C) -> Option<T>
15    where
16        C: Fn(Oid) -> Option<T>,
17    {
18        if let Some(result) = callback(commit_id) {
19            Some(result)
20        } else {
21            let parent_id = self.find_commit(commit_id).ok()?.parent(0).ok()?.id();
22            self.walk_history(parent_id, callback)
23        }
24    }
25    fn iter_commit_id<'repo>(&'repo self, commit: &'repo Commit) -> CommitIdIter<'repo> {
26        CommitIdIter {
27            repo: self,
28            started: false,
29            cursor: commit.id(),
30        }
31    }
32}
33
34pub struct CommitIdIter<'a> {
35    repo: &'a Repository,
36    started: bool,
37    cursor: Oid,
38}
39
40impl<'a> Iterator for CommitIdIter<'a> {
41    type Item = Oid;
42    fn next(&mut self) -> Option<Oid> {
43        if !self.started {
44            self.started = true;
45            Some(self.cursor)
46        } else {
47            let current = self.repo.find_commit(self.cursor).ok()?;
48            if let Ok(next_commit) = current.parent(0) {
49                self.cursor = next_commit.id();
50                Some(self.cursor)
51            } else {
52                None
53            }
54        }
55    }
56}