use crate::error::Result;
use crate::object_inspect::{ResolveError, ResolvedObject};
use crate::objects::ObjectId;
use crate::repo::Repository;
use crate::rev_list::{rev_list, RevListOptions, RevListResult};
use crate::rev_list_error::RevListError;
use crate::rev_parse::resolve_revision;
use crate::revwalk::parse_rev_walk_tokens;
use std::borrow::Cow;
#[derive(Debug, Copy, Clone)]
pub struct RevWalk<'repo> {
repo: &'repo Repository,
}
impl<'repo> RevWalk<'repo> {
#[inline]
#[must_use]
pub fn new(repo: &'repo Repository) -> Self {
Self { repo }
}
#[inline]
#[must_use]
pub fn repository(&self) -> &'repo Repository {
self.repo
}
#[inline]
pub fn resolve(&self, spec: &str) -> Result<ObjectId> {
resolve_revision(self.repo, spec)
}
#[inline]
pub fn resolve_object(&self, spec: &str) -> std::result::Result<ResolvedObject, ResolveError> {
self.repo.resolve(spec)
}
pub fn walk(&self, spec: &str, options: &RevListOptions) -> Result<RevListResult> {
if !is_single_walk_spec(spec) {
return Err(RevListError::UnsupportedWalkSpec {
spec: spec.to_owned(),
}
.into());
}
let parsed = parse_rev_walk_tokens(self.repo, &[spec])?;
let options = if parsed.symmetric_left.is_some()
&& (options.symmetric_left.is_none() || options.symmetric_right.is_none())
{
let mut symmetric = options.clone();
symmetric.symmetric_left = symmetric.symmetric_left.or(parsed.symmetric_left);
symmetric.symmetric_right = symmetric.symmetric_right.or(parsed.symmetric_right);
Cow::Owned(symmetric)
} else {
Cow::Borrowed(options)
};
rev_list(self.repo, &parsed.positive, &parsed.negative, &options)
}
}
fn is_single_walk_spec(spec: &str) -> bool {
if spec.starts_with('-') {
return false;
}
let mut brace_depth = 0usize;
for c in spec.chars() {
match c {
':' if brace_depth == 0 => return true,
'{' => brace_depth += 1,
'}' => brace_depth = brace_depth.saturating_sub(1),
c if c.is_whitespace() && brace_depth == 0 => return false,
_ => {}
}
}
true
}