use std::ops::{Bound, RangeBounds};
use crate::repository::id::Id;
use crate::repository::{Error, Repository, Result};
use super::commit::Commit;
pub struct Commits<'a> {
repository: &'a Repository,
revwalk: git2::Revwalk<'a>,
end: Option<Id>,
}
impl Repository {
pub fn commits<R>(&self, range: R) -> Result<Commits<'_>>
where
R: RangeBounds<Id>,
{
let mut revwalk = self.inner.revwalk()?;
revwalk.set_sorting(git2::Sort::TOPOLOGICAL)?;
let end = match (range.start_bound(), range.end_bound()) {
(Bound::Unbounded, Bound::Unbounded) => {
revwalk.push_head()?;
None
}
(Bound::Unbounded, Bound::Excluded(end)) => {
revwalk.push_head()?;
Some(*end)
}
(Bound::Included(start), Bound::Unbounded) => {
revwalk.push(**start)?;
None
}
(Bound::Included(start), Bound::Excluded(end)) => {
revwalk.push(**start)?;
Some(*end)
}
(Bound::Excluded(_), _) | (_, Bound::Included(_)) => {
return Err(Error::Bound);
}
};
Ok(Commits { repository: self, revwalk, end })
}
}
impl<'a> Iterator for Commits<'a> {
type Item = Result<Commit<'a>>;
fn next(&mut self) -> Option<Self::Item> {
let id = match self.revwalk.next()? {
Ok(id) => id,
Err(err) => return Some(Err(err.into())),
};
if self.end.as_deref() == Some(&id) {
None
} else {
Some(self.repository.get(id))
}
}
}