revset: move internal_evaluate() onto new context type

I'm about to replace the `&dyn Repo` argument by several smaller
types, and it's easier to collect those in a single context type than
to pass them separately as arguments.

I also moved `revset_for_commit_ids()` and `take_latest_revset()` onto
the new type because it was easy. `build_predicate_fn()` and
`has_diff_from_parent()` ran into some lifetime issue when I tried.
This commit is contained in:
Martin von Zweigbergk 2023-03-30 09:34:03 -07:00 committed by Martin von Zweigbergk
parent 3ff1ab520b
commit 002ec1ac68

View file

@ -496,14 +496,20 @@ pub fn evaluate<'index>(
index: CompositeIndex<'index>, index: CompositeIndex<'index>,
expression: &RevsetExpression, expression: &RevsetExpression,
) -> Result<RevsetImpl<'index>, RevsetError> { ) -> Result<RevsetImpl<'index>, RevsetError> {
let internal_revset = internal_evaluate(repo, expression)?; let context = EvaluationContext { repo };
let internal_revset = context.evaluate(expression)?;
Ok(RevsetImpl::new(internal_revset, index)) Ok(RevsetImpl::new(internal_revset, index))
} }
fn internal_evaluate<'index>( struct EvaluationContext<'index> {
repo: &'index dyn Repo, repo: &'index dyn Repo,
}
impl<'index> EvaluationContext<'index> {
fn evaluate(
&self,
expression: &RevsetExpression, expression: &RevsetExpression,
) -> Result<Box<dyn InternalRevset<'index> + 'index>, RevsetError> { ) -> Result<Box<dyn InternalRevset<'index> + 'index>, RevsetError> {
match expression { match expression {
RevsetExpression::Symbol(_) RevsetExpression::Symbol(_)
| RevsetExpression::Branches(_) | RevsetExpression::Branches(_)
@ -522,13 +528,13 @@ fn internal_evaluate<'index>(
// (and `remote_branches()`) specified in the revset expression. Alternatively, // (and `remote_branches()`) specified in the revset expression. Alternatively,
// some optimization rules could be removed, but that means `author(_) & x` // some optimization rules could be removed, but that means `author(_) & x`
// would have to test `:heads() & x`. // would have to test `:heads() & x`.
internal_evaluate(repo, &RevsetExpression::visible_heads().ancestors()) self.evaluate(&RevsetExpression::visible_heads().ancestors())
} }
RevsetExpression::Commits(commit_ids) => Ok(revset_for_commit_ids(repo, commit_ids)), RevsetExpression::Commits(commit_ids) => Ok(self.revset_for_commit_ids(commit_ids)),
RevsetExpression::Children(roots) => { RevsetExpression::Children(roots) => {
let root_set = internal_evaluate(repo, roots)?; let root_set = self.evaluate(roots)?;
let candidates_expression = roots.descendants(); let candidates_expression = roots.descendants();
let candidate_set = internal_evaluate(repo, &candidates_expression)?; let candidate_set = self.evaluate(&candidates_expression)?;
Ok(Box::new(ChildrenRevset { Ok(Box::new(ChildrenRevset {
root_set, root_set,
candidate_set, candidate_set,
@ -540,18 +546,18 @@ fn internal_evaluate<'index>(
heads: heads.clone(), heads: heads.clone(),
generation: generation.clone(), generation: generation.clone(),
}; };
internal_evaluate(repo, &range_expression) self.evaluate(&range_expression)
} }
RevsetExpression::Range { RevsetExpression::Range {
roots, roots,
heads, heads,
generation, generation,
} => { } => {
let root_set = internal_evaluate(repo, roots)?; let root_set = self.evaluate(roots)?;
let root_ids = root_set.iter().map(|entry| entry.commit_id()).collect_vec(); let root_ids = root_set.iter().map(|entry| entry.commit_id()).collect_vec();
let head_set = internal_evaluate(repo, heads)?; let head_set = self.evaluate(heads)?;
let head_ids = head_set.iter().map(|entry| entry.commit_id()).collect_vec(); let head_ids = head_set.iter().map(|entry| entry.commit_id()).collect_vec();
let walk = repo.index().walk_revs(&head_ids, &root_ids); let walk = self.repo.index().walk_revs(&head_ids, &root_ids);
if generation == &GENERATION_RANGE_FULL { if generation == &GENERATION_RANGE_FULL {
Ok(Box::new(RevWalkRevset { walk })) Ok(Box::new(RevWalkRevset { walk }))
} else { } else {
@ -560,9 +566,10 @@ fn internal_evaluate<'index>(
} }
} }
RevsetExpression::DagRange { roots, heads } => { RevsetExpression::DagRange { roots, heads } => {
let root_set = internal_evaluate(repo, roots)?; let root_set = self.evaluate(roots)?;
let candidate_set = internal_evaluate(repo, &heads.ancestors())?; let candidate_set = self.evaluate(&heads.ancestors())?;
let mut reachable: HashSet<_> = root_set.iter().map(|entry| entry.position()).collect(); let mut reachable: HashSet<_> =
root_set.iter().map(|entry| entry.position()).collect();
let mut result = vec![]; let mut result = vec![];
let candidates = candidate_set.iter().collect_vec(); let candidates = candidate_set.iter().collect_vec();
for candidate in candidates.into_iter().rev() { for candidate in candidates.into_iter().rev() {
@ -581,26 +588,24 @@ fn internal_evaluate<'index>(
index_entries: result, index_entries: result,
})) }))
} }
RevsetExpression::VisibleHeads => Ok(revset_for_commit_ids( RevsetExpression::VisibleHeads => {
repo, Ok(self
&repo.view().heads().iter().cloned().collect_vec(), .revset_for_commit_ids(&self.repo.view().heads().iter().cloned().collect_vec()))
)), }
RevsetExpression::Heads(candidates) => { RevsetExpression::Heads(candidates) => {
let candidate_set = internal_evaluate(repo, candidates)?; let candidate_set = self.evaluate(candidates)?;
let candidate_ids = candidate_set let candidate_ids = candidate_set
.iter() .iter()
.map(|entry| entry.commit_id()) .map(|entry| entry.commit_id())
.collect_vec(); .collect_vec();
Ok(revset_for_commit_ids( Ok(self.revset_for_commit_ids(&self.repo.index().heads(&mut candidate_ids.iter())))
repo,
&repo.index().heads(&mut candidate_ids.iter()),
))
} }
RevsetExpression::Roots(candidates) => { RevsetExpression::Roots(candidates) => {
let connected_set = internal_evaluate(repo, &candidates.connected())?; let connected_set = self.evaluate(&candidates.connected())?;
let filled: HashSet<_> = connected_set.iter().map(|entry| entry.position()).collect(); let filled: HashSet<_> =
connected_set.iter().map(|entry| entry.position()).collect();
let mut index_entries = vec![]; let mut index_entries = vec![];
let candidate_set = internal_evaluate(repo, candidates)?; let candidate_set = self.evaluate(candidates)?;
for candidate in candidate_set.iter() { for candidate in candidate_set.iter() {
if !candidate if !candidate
.parent_positions() .parent_positions()
@ -613,61 +618,61 @@ fn internal_evaluate<'index>(
Ok(Box::new(EagerRevset { index_entries })) Ok(Box::new(EagerRevset { index_entries }))
} }
RevsetExpression::Latest { candidates, count } => { RevsetExpression::Latest { candidates, count } => {
let candidate_set = internal_evaluate(repo, candidates)?; let candidate_set = self.evaluate(candidates)?;
Ok(take_latest_revset(repo, candidate_set.as_ref(), *count)) Ok(self.take_latest_revset(candidate_set.as_ref(), *count))
} }
RevsetExpression::Filter(predicate) => Ok(Box::new(FilterRevset { RevsetExpression::Filter(predicate) => Ok(Box::new(FilterRevset {
candidates: internal_evaluate(repo, &RevsetExpression::All)?, candidates: self.evaluate(&RevsetExpression::All)?,
predicate: build_predicate_fn(repo, predicate), predicate: build_predicate_fn(self.repo, predicate),
})), })),
RevsetExpression::AsFilter(candidates) => internal_evaluate(repo, candidates), RevsetExpression::AsFilter(candidates) => self.evaluate(candidates),
RevsetExpression::Present(candidates) => match internal_evaluate(repo, candidates) { RevsetExpression::Present(candidates) => match self.evaluate(candidates) {
Ok(set) => Ok(set), Ok(set) => Ok(set),
Err(RevsetError::NoSuchRevision(_)) => Ok(Box::new(EagerRevset::empty())), Err(RevsetError::NoSuchRevision(_)) => Ok(Box::new(EagerRevset::empty())),
r @ Err(RevsetError::AmbiguousIdPrefix(_) | RevsetError::StoreError(_)) => r, r @ Err(RevsetError::AmbiguousIdPrefix(_) | RevsetError::StoreError(_)) => r,
}, },
RevsetExpression::NotIn(complement) => { RevsetExpression::NotIn(complement) => {
let set1 = internal_evaluate(repo, &RevsetExpression::All)?; let set1 = self.evaluate(&RevsetExpression::All)?;
let set2 = internal_evaluate(repo, complement)?; let set2 = self.evaluate(complement)?;
Ok(Box::new(DifferenceRevset { set1, set2 })) Ok(Box::new(DifferenceRevset { set1, set2 }))
} }
RevsetExpression::Union(expression1, expression2) => { RevsetExpression::Union(expression1, expression2) => {
let set1 = internal_evaluate(repo, expression1)?; let set1 = self.evaluate(expression1)?;
let set2 = internal_evaluate(repo, expression2)?; let set2 = self.evaluate(expression2)?;
Ok(Box::new(UnionRevset { set1, set2 })) Ok(Box::new(UnionRevset { set1, set2 }))
} }
RevsetExpression::Intersection(expression1, expression2) => { RevsetExpression::Intersection(expression1, expression2) => {
match expression2.as_ref() { match expression2.as_ref() {
RevsetExpression::Filter(predicate) => Ok(Box::new(FilterRevset { RevsetExpression::Filter(predicate) => Ok(Box::new(FilterRevset {
candidates: internal_evaluate(repo, expression1)?, candidates: self.evaluate(expression1)?,
predicate: build_predicate_fn(repo, predicate), predicate: build_predicate_fn(self.repo, predicate),
})), })),
RevsetExpression::AsFilter(expression2) => Ok(Box::new(FilterRevset { RevsetExpression::AsFilter(expression2) => Ok(Box::new(FilterRevset {
candidates: internal_evaluate(repo, expression1)?, candidates: self.evaluate(expression1)?,
predicate: internal_evaluate(repo, expression2)?, predicate: self.evaluate(expression2)?,
})), })),
_ => { _ => {
// TODO: 'set2' can be turned into a predicate, and use FilterRevset // TODO: 'set2' can be turned into a predicate, and use FilterRevset
// if a predicate function can terminate the 'set1' iterator early. // if a predicate function can terminate the 'set1' iterator early.
let set1 = internal_evaluate(repo, expression1)?; let set1 = self.evaluate(expression1)?;
let set2 = internal_evaluate(repo, expression2)?; let set2 = self.evaluate(expression2)?;
Ok(Box::new(IntersectionRevset { set1, set2 })) Ok(Box::new(IntersectionRevset { set1, set2 }))
} }
} }
} }
RevsetExpression::Difference(expression1, expression2) => { RevsetExpression::Difference(expression1, expression2) => {
let set1 = internal_evaluate(repo, expression1)?; let set1 = self.evaluate(expression1)?;
let set2 = internal_evaluate(repo, expression2)?; let set2 = self.evaluate(expression2)?;
Ok(Box::new(DifferenceRevset { set1, set2 })) Ok(Box::new(DifferenceRevset { set1, set2 }))
} }
} }
} }
fn revset_for_commit_ids<'index>( fn revset_for_commit_ids(
repo: &'index dyn Repo, &self,
commit_ids: &[CommitId], commit_ids: &[CommitId],
) -> Box<dyn InternalRevset<'index> + 'index> { ) -> Box<dyn InternalRevset<'index> + 'index> {
let index = repo.index(); let index = self.repo.index();
let mut index_entries = vec![]; let mut index_entries = vec![];
for id in commit_ids { for id in commit_ids {
index_entries.push(index.entry_by_id(id).unwrap()); index_entries.push(index.entry_by_id(id).unwrap());
@ -675,13 +680,13 @@ fn revset_for_commit_ids<'index>(
index_entries.sort_unstable_by_key(|b| Reverse(b.position())); index_entries.sort_unstable_by_key(|b| Reverse(b.position()));
index_entries.dedup(); index_entries.dedup();
Box::new(EagerRevset { index_entries }) Box::new(EagerRevset { index_entries })
} }
fn take_latest_revset<'index>( fn take_latest_revset(
repo: &dyn Repo, &self,
candidate_set: &dyn InternalRevset<'index>, candidate_set: &dyn InternalRevset<'index>,
count: usize, count: usize,
) -> Box<dyn InternalRevset<'index> + 'index> { ) -> Box<dyn InternalRevset<'index> + 'index> {
if count == 0 { if count == 0 {
return Box::new(EagerRevset::empty()); return Box::new(EagerRevset::empty());
} }
@ -692,7 +697,7 @@ fn take_latest_revset<'index>(
entry: IndexEntryByPosition<'a>, // tie-breaker entry: IndexEntryByPosition<'a>, // tie-breaker
} }
let store = repo.store(); let store = self.repo.store();
let make_rev_item = |entry: IndexEntry<'index>| { let make_rev_item = |entry: IndexEntry<'index>| {
let commit = store.get_commit(&entry.commit_id()).unwrap(); let commit = store.get_commit(&entry.commit_id()).unwrap();
Reverse(Item { Reverse(Item {
@ -720,6 +725,7 @@ fn take_latest_revset<'index>(
.collect_vec(); .collect_vec();
index_entries.sort_unstable_by_key(|b| Reverse(b.position())); index_entries.sort_unstable_by_key(|b| Reverse(b.position()));
Box::new(EagerRevset { index_entries }) Box::new(EagerRevset { index_entries })
}
} }
type PurePredicateFn<'index> = Box<dyn Fn(&IndexEntry<'index>) -> bool + 'index>; type PurePredicateFn<'index> = Box<dyn Fn(&IndexEntry<'index>) -> bool + 'index>;