1#![allow(missing_docs)]
16
17use std::cell::RefCell;
18use std::cmp::Ordering;
19use std::cmp::Reverse;
20use std::collections::BTreeSet;
21use std::collections::BinaryHeap;
22use std::collections::HashSet;
23use std::fmt;
24use std::iter;
25use std::ops::Range;
26use std::rc::Rc;
27use std::str;
28use std::sync::Arc;
29
30use futures::StreamExt as _;
31use itertools::Itertools as _;
32use pollster::FutureExt as _;
33
34use super::rev_walk::EagerRevWalk;
35use super::rev_walk::PeekableRevWalk;
36use super::rev_walk::RevWalk;
37use super::rev_walk::RevWalkBuilder;
38use super::revset_graph_iterator::RevsetGraphWalk;
39use crate::backend::BackendResult;
40use crate::backend::ChangeId;
41use crate::backend::CommitId;
42use crate::backend::MillisSinceEpoch;
43use crate::commit::Commit;
44use crate::conflicts::materialize_merge_result_to_bytes;
45use crate::conflicts::materialize_tree_value;
46use crate::conflicts::ConflictMarkerStyle;
47use crate::conflicts::MaterializedTreeValue;
48use crate::default_index::AsCompositeIndex;
49use crate::default_index::CompositeIndex;
50use crate::default_index::IndexPosition;
51use crate::graph::GraphNode;
52use crate::matchers::Matcher;
53use crate::matchers::Visit;
54use crate::merged_tree::resolve_file_values;
55use crate::object_id::ObjectId as _;
56use crate::repo_path::RepoPath;
57use crate::revset::ResolvedExpression;
58use crate::revset::ResolvedPredicateExpression;
59use crate::revset::Revset;
60use crate::revset::RevsetContainingFn;
61use crate::revset::RevsetEvaluationError;
62use crate::revset::RevsetFilterPredicate;
63use crate::revset::GENERATION_RANGE_FULL;
64use crate::rewrite;
65use crate::store::Store;
66use crate::str_util::StringPattern;
67use crate::union_find;
68
69type BoxedPredicateFn<'a> =
70 Box<dyn FnMut(&CompositeIndex, IndexPosition) -> Result<bool, RevsetEvaluationError> + 'a>;
71pub(super) type BoxedRevWalk<'a> =
72 Box<dyn RevWalk<CompositeIndex, Item = Result<IndexPosition, RevsetEvaluationError>> + 'a>;
73
74trait ToPredicateFn: fmt::Debug {
75 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
79 where
80 Self: 'a;
81}
82
83impl<T: ToPredicateFn + ?Sized> ToPredicateFn for Box<T> {
84 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
85 where
86 Self: 'a,
87 {
88 <T as ToPredicateFn>::to_predicate_fn(self)
89 }
90}
91
92trait InternalRevset: fmt::Debug + ToPredicateFn {
93 fn positions<'a>(&self) -> BoxedRevWalk<'a>
95 where
96 Self: 'a;
97
98 fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
99 where
100 Self: 'a;
101}
102
103impl<T: InternalRevset + ?Sized> InternalRevset for Box<T> {
104 fn positions<'a>(&self) -> BoxedRevWalk<'a>
105 where
106 Self: 'a,
107 {
108 <T as InternalRevset>::positions(self)
109 }
110
111 fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
112 where
113 Self: 'a,
114 {
115 <T as InternalRevset>::into_predicate(*self)
116 }
117}
118
119pub struct RevsetImpl<I> {
120 inner: Box<dyn InternalRevset>,
121 index: I,
122}
123
124impl<I: AsCompositeIndex + Clone> RevsetImpl<I> {
125 fn new(inner: Box<dyn InternalRevset>, index: I) -> Self {
126 Self { inner, index }
127 }
128
129 fn positions(
130 &self,
131 ) -> impl Iterator<Item = Result<IndexPosition, RevsetEvaluationError>> + use<'_, I> {
132 self.inner.positions().attach(self.index.as_composite())
133 }
134
135 pub fn iter_graph_impl(
136 &self,
137 skip_transitive_edges: bool,
138 ) -> impl Iterator<Item = Result<GraphNode<CommitId>, RevsetEvaluationError>> + use<I> {
139 let index = self.index.clone();
140 let walk = self.inner.positions();
141 let mut graph_walk = RevsetGraphWalk::new(walk, skip_transitive_edges);
142 iter::from_fn(move || graph_walk.next(index.as_composite()))
143 }
144}
145
146impl<I> fmt::Debug for RevsetImpl<I> {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 f.debug_struct("RevsetImpl")
149 .field("inner", &self.inner)
150 .finish_non_exhaustive()
151 }
152}
153
154impl<I: AsCompositeIndex + Clone> Revset for RevsetImpl<I> {
155 fn iter<'a>(&self) -> Box<dyn Iterator<Item = Result<CommitId, RevsetEvaluationError>> + 'a>
156 where
157 Self: 'a,
158 {
159 let index = self.index.clone();
160 let mut walk = self
161 .inner
162 .positions()
163 .map(|index, pos| Ok(index.entry_by_pos(pos?).commit_id()));
164 Box::new(iter::from_fn(move || walk.next(index.as_composite())))
165 }
166
167 fn commit_change_ids<'a>(
168 &self,
169 ) -> Box<dyn Iterator<Item = Result<(CommitId, ChangeId), RevsetEvaluationError>> + 'a>
170 where
171 Self: 'a,
172 {
173 let index = self.index.clone();
174 let mut walk = self.inner.positions().map(|index, pos| {
175 let entry = index.entry_by_pos(pos?);
176 Ok((entry.commit_id(), entry.change_id()))
177 });
178 Box::new(iter::from_fn(move || walk.next(index.as_composite())))
179 }
180
181 fn iter_graph<'a>(
182 &self,
183 ) -> Box<dyn Iterator<Item = Result<GraphNode<CommitId>, RevsetEvaluationError>> + 'a>
184 where
185 Self: 'a,
186 {
187 let skip_transitive_edges = true;
188 Box::new(self.iter_graph_impl(skip_transitive_edges))
189 }
190
191 fn is_empty(&self) -> bool {
192 self.positions().next().is_none()
193 }
194
195 fn count_estimate(&self) -> Result<(usize, Option<usize>), RevsetEvaluationError> {
196 if cfg!(feature = "testing") {
197 let count = self
201 .positions()
202 .take(10)
203 .process_results(|iter| iter.count())?;
204 if count < 10 {
205 Ok((count, Some(count)))
206 } else {
207 Ok((10, None))
208 }
209 } else {
210 let count = self.positions().process_results(|iter| iter.count())?;
211 Ok((count, Some(count)))
212 }
213 }
214
215 fn containing_fn<'a>(&self) -> Box<RevsetContainingFn<'a>>
216 where
217 Self: 'a,
218 {
219 let positions = PositionsAccumulator::new(self.index.clone(), self.inner.positions());
220 Box::new(move |commit_id| positions.contains(commit_id))
221 }
222}
223
224struct PositionsAccumulator<'a, I> {
226 index: I,
227 inner: RefCell<PositionsAccumulatorInner<'a>>,
228}
229
230impl<'a, I: AsCompositeIndex> PositionsAccumulator<'a, I> {
231 fn new(index: I, walk: BoxedRevWalk<'a>) -> Self {
232 let inner = RefCell::new(PositionsAccumulatorInner {
233 walk,
234 consumed_positions: Vec::new(),
235 });
236 PositionsAccumulator { index, inner }
237 }
238
239 fn contains(&self, commit_id: &CommitId) -> Result<bool, RevsetEvaluationError> {
241 let index = self.index.as_composite();
242 let Some(position) = index.commit_id_to_pos(commit_id) else {
243 return Ok(false);
244 };
245
246 let mut inner = self.inner.borrow_mut();
247 inner.consume_to(index, position)?;
248 let found = inner
249 .consumed_positions
250 .binary_search_by(|p| p.cmp(&position).reverse())
251 .is_ok();
252 Ok(found)
253 }
254
255 #[cfg(test)]
256 fn consumed_len(&self) -> usize {
257 self.inner.borrow().consumed_positions.len()
258 }
259}
260
261struct PositionsAccumulatorInner<'a> {
263 walk: BoxedRevWalk<'a>,
264 consumed_positions: Vec<IndexPosition>,
265}
266
267impl PositionsAccumulatorInner<'_> {
268 fn consume_to(
270 &mut self,
271 index: &CompositeIndex,
272 desired_position: IndexPosition,
273 ) -> Result<(), RevsetEvaluationError> {
274 let last_position = self.consumed_positions.last();
275 if last_position.is_some_and(|&pos| pos <= desired_position) {
276 return Ok(());
277 }
278 while let Some(position) = self.walk.next(index).transpose()? {
279 self.consumed_positions.push(position);
280 if position <= desired_position {
281 return Ok(());
282 }
283 }
284 Ok(())
285 }
286}
287
288#[derive(Debug)]
290struct EagerRevset {
291 positions: Vec<IndexPosition>,
292}
293
294impl EagerRevset {
295 pub const fn empty() -> Self {
296 EagerRevset {
297 positions: Vec::new(),
298 }
299 }
300}
301
302impl InternalRevset for EagerRevset {
303 fn positions<'a>(&self) -> BoxedRevWalk<'a>
304 where
305 Self: 'a,
306 {
307 let walk = EagerRevWalk::new(self.positions.clone().into_iter());
308 Box::new(walk.map(|_index, pos| Ok(pos)))
309 }
310
311 fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
312 where
313 Self: 'a,
314 {
315 self
316 }
317}
318
319impl ToPredicateFn for EagerRevset {
320 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
321 where
322 Self: 'a,
323 {
324 let walk = EagerRevWalk::new(self.positions.clone().into_iter());
325 predicate_fn_from_rev_walk(walk)
326 }
327}
328
329struct RevWalkRevset<W> {
331 walk: W,
332}
333
334impl<W> fmt::Debug for RevWalkRevset<W> {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 f.debug_struct("RevWalkRevset").finish_non_exhaustive()
337 }
338}
339
340impl<W> InternalRevset for RevWalkRevset<W>
341where
342 W: RevWalk<CompositeIndex, Item = IndexPosition> + Clone,
343{
344 fn positions<'a>(&self) -> BoxedRevWalk<'a>
345 where
346 Self: 'a,
347 {
348 Box::new(self.walk.clone().map(|_index, pos| Ok(pos)))
349 }
350
351 fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
352 where
353 Self: 'a,
354 {
355 self
356 }
357}
358
359impl<W> ToPredicateFn for RevWalkRevset<W>
360where
361 W: RevWalk<CompositeIndex, Item = IndexPosition> + Clone,
362{
363 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
364 where
365 Self: 'a,
366 {
367 predicate_fn_from_rev_walk(self.walk.clone())
368 }
369}
370
371fn predicate_fn_from_rev_walk<'a, W>(walk: W) -> BoxedPredicateFn<'a>
372where
373 W: RevWalk<CompositeIndex, Item = IndexPosition> + 'a,
374{
375 let mut walk = walk.peekable();
376 Box::new(move |index, entry_pos| {
377 while walk.next_if(index, |&pos| pos > entry_pos).is_some() {
378 continue;
379 }
380 Ok(walk.next_if(index, |&pos| pos == entry_pos).is_some())
381 })
382}
383
384#[derive(Debug)]
385struct FilterRevset<S, P> {
386 candidates: S,
387 predicate: P,
388}
389
390impl<S, P> InternalRevset for FilterRevset<S, P>
391where
392 S: InternalRevset,
393 P: ToPredicateFn,
394{
395 fn positions<'a>(&self) -> BoxedRevWalk<'a>
396 where
397 Self: 'a,
398 {
399 let mut p = self.predicate.to_predicate_fn();
400 Box::new(self.candidates.positions().filter_map(move |index, pos| {
401 pos.and_then(|pos| Ok(p(index, pos)?.then_some(pos)))
402 .transpose()
403 }))
404 }
405
406 fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
407 where
408 Self: 'a,
409 {
410 self
411 }
412}
413
414impl<S, P> ToPredicateFn for FilterRevset<S, P>
415where
416 S: ToPredicateFn,
417 P: ToPredicateFn,
418{
419 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
420 where
421 Self: 'a,
422 {
423 let mut p1 = self.candidates.to_predicate_fn();
424 let mut p2 = self.predicate.to_predicate_fn();
425 Box::new(move |index, pos| Ok(p1(index, pos)? && p2(index, pos)?))
426 }
427}
428
429#[derive(Debug)]
430struct NotInPredicate<S>(S);
431
432impl<S: ToPredicateFn> ToPredicateFn for NotInPredicate<S> {
433 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
434 where
435 Self: 'a,
436 {
437 let mut p = self.0.to_predicate_fn();
438 Box::new(move |index, pos| Ok(!p(index, pos)?))
439 }
440}
441
442#[derive(Debug)]
443struct UnionRevset<S1, S2> {
444 set1: S1,
445 set2: S2,
446}
447
448impl<S1, S2> InternalRevset for UnionRevset<S1, S2>
449where
450 S1: InternalRevset,
451 S2: InternalRevset,
452{
453 fn positions<'a>(&self) -> BoxedRevWalk<'a>
454 where
455 Self: 'a,
456 {
457 Box::new(union_by(
458 self.set1.positions(),
459 self.set2.positions(),
460 |pos1, pos2| pos1.cmp(pos2).reverse(),
461 ))
462 }
463
464 fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
465 where
466 Self: 'a,
467 {
468 self
469 }
470}
471
472impl<S1, S2> ToPredicateFn for UnionRevset<S1, S2>
473where
474 S1: ToPredicateFn,
475 S2: ToPredicateFn,
476{
477 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
478 where
479 Self: 'a,
480 {
481 let mut p1 = self.set1.to_predicate_fn();
482 let mut p2 = self.set2.to_predicate_fn();
483 Box::new(move |index, pos| Ok(p1(index, pos)? || p2(index, pos)?))
484 }
485}
486
487struct UnionRevWalk<I: ?Sized, W1: RevWalk<I>, W2: RevWalk<I>, C> {
491 walk1: PeekableRevWalk<I, W1>,
492 walk2: PeekableRevWalk<I, W2>,
493 cmp: C,
494}
495
496impl<I, T, E, W1, W2, C> RevWalk<I> for UnionRevWalk<I, W1, W2, C>
497where
498 I: ?Sized,
499 W1: RevWalk<I, Item = Result<T, E>>,
500 W2: RevWalk<I, Item = Result<T, E>>,
501 C: FnMut(&T, &T) -> Ordering,
502{
503 type Item = W1::Item;
504
505 fn next(&mut self, index: &I) -> Option<Self::Item> {
506 match (self.walk1.peek(index), self.walk2.peek(index)) {
507 (None, _) => self.walk2.next(index),
508 (_, None) => self.walk1.next(index),
509 (Some(Ok(item1)), Some(Ok(item2))) => match (self.cmp)(item1, item2) {
510 Ordering::Less => self.walk1.next(index),
511 Ordering::Equal => {
512 self.walk2.next(index);
513 self.walk1.next(index)
514 }
515 Ordering::Greater => self.walk2.next(index),
516 },
517 (Some(Err(_)), _) => self.walk1.next(index),
518 (_, Some(Err(_))) => self.walk2.next(index),
519 }
520 }
521}
522
523fn union_by<I, T, E, W1, W2, C>(walk1: W1, walk2: W2, cmp: C) -> UnionRevWalk<I, W1, W2, C>
524where
525 I: ?Sized,
526 W1: RevWalk<I, Item = Result<T, E>>,
527 W2: RevWalk<I, Item = Result<T, E>>,
528 C: FnMut(&T, &T) -> Ordering,
529{
530 UnionRevWalk {
531 walk1: walk1.peekable(),
532 walk2: walk2.peekable(),
533 cmp,
534 }
535}
536
537#[derive(Debug)]
538struct IntersectionRevset<S1, S2> {
539 set1: S1,
540 set2: S2,
541}
542
543impl<S1, S2> InternalRevset for IntersectionRevset<S1, S2>
544where
545 S1: InternalRevset,
546 S2: InternalRevset,
547{
548 fn positions<'a>(&self) -> BoxedRevWalk<'a>
549 where
550 Self: 'a,
551 {
552 Box::new(intersection_by(
553 self.set1.positions(),
554 self.set2.positions(),
555 |pos1, pos2| pos1.cmp(pos2).reverse(),
556 ))
557 }
558
559 fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
560 where
561 Self: 'a,
562 {
563 self
564 }
565}
566
567impl<S1, S2> ToPredicateFn for IntersectionRevset<S1, S2>
568where
569 S1: ToPredicateFn,
570 S2: ToPredicateFn,
571{
572 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
573 where
574 Self: 'a,
575 {
576 let mut p1 = self.set1.to_predicate_fn();
577 let mut p2 = self.set2.to_predicate_fn();
578 Box::new(move |index, pos| Ok(p1(index, pos)? && p2(index, pos)?))
579 }
580}
581
582struct IntersectionRevWalk<I: ?Sized, W1: RevWalk<I>, W2: RevWalk<I>, C> {
586 walk1: PeekableRevWalk<I, W1>,
587 walk2: PeekableRevWalk<I, W2>,
588 cmp: C,
589}
590
591impl<I, T, E, W1, W2, C> RevWalk<I> for IntersectionRevWalk<I, W1, W2, C>
592where
593 I: ?Sized,
594 W1: RevWalk<I, Item = Result<T, E>>,
595 W2: RevWalk<I, Item = Result<T, E>>,
596 C: FnMut(&T, &T) -> Ordering,
597{
598 type Item = W1::Item;
599
600 fn next(&mut self, index: &I) -> Option<Self::Item> {
601 loop {
602 match (self.walk1.peek(index), self.walk2.peek(index)) {
603 (None, _) => {
604 return None;
605 }
606 (_, None) => {
607 return None;
608 }
609 (Some(Ok(item1)), Some(Ok(item2))) => match (self.cmp)(item1, item2) {
610 Ordering::Less => {
611 self.walk1.next(index);
612 }
613 Ordering::Equal => {
614 self.walk2.next(index);
615 return self.walk1.next(index);
616 }
617 Ordering::Greater => {
618 self.walk2.next(index);
619 }
620 },
621 (Some(Err(_)), _) => {
622 return self.walk1.next(index);
623 }
624 (_, Some(Err(_))) => {
625 return self.walk2.next(index);
626 }
627 }
628 }
629 }
630}
631
632fn intersection_by<I, T, E, W1, W2, C>(
633 walk1: W1,
634 walk2: W2,
635 cmp: C,
636) -> IntersectionRevWalk<I, W1, W2, C>
637where
638 I: ?Sized,
639 W1: RevWalk<I, Item = Result<T, E>>,
640 W2: RevWalk<I, Item = Result<T, E>>,
641 C: FnMut(&T, &T) -> Ordering,
642{
643 IntersectionRevWalk {
644 walk1: walk1.peekable(),
645 walk2: walk2.peekable(),
646 cmp,
647 }
648}
649
650#[derive(Debug)]
651struct DifferenceRevset<S1, S2> {
652 set1: S1,
654 set2: S2,
656}
657
658impl<S1, S2> InternalRevset for DifferenceRevset<S1, S2>
659where
660 S1: InternalRevset,
661 S2: InternalRevset,
662{
663 fn positions<'a>(&self) -> BoxedRevWalk<'a>
664 where
665 Self: 'a,
666 {
667 Box::new(difference_by(
668 self.set1.positions(),
669 self.set2.positions(),
670 |pos1, pos2| pos1.cmp(pos2).reverse(),
671 ))
672 }
673
674 fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
675 where
676 Self: 'a,
677 {
678 self
679 }
680}
681
682impl<S1, S2> ToPredicateFn for DifferenceRevset<S1, S2>
683where
684 S1: ToPredicateFn,
685 S2: ToPredicateFn,
686{
687 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
688 where
689 Self: 'a,
690 {
691 let mut p1 = self.set1.to_predicate_fn();
692 let mut p2 = self.set2.to_predicate_fn();
693 Box::new(move |index, pos| Ok(p1(index, pos)? && !p2(index, pos)?))
694 }
695}
696
697struct DifferenceRevWalk<I: ?Sized, W1: RevWalk<I>, W2: RevWalk<I>, C> {
701 walk1: PeekableRevWalk<I, W1>,
702 walk2: PeekableRevWalk<I, W2>,
703 cmp: C,
704}
705
706impl<I, T, E, W1, W2, C> RevWalk<I> for DifferenceRevWalk<I, W1, W2, C>
707where
708 I: ?Sized,
709 W1: RevWalk<I, Item = Result<T, E>>,
710 W2: RevWalk<I, Item = Result<T, E>>,
711 C: FnMut(&T, &T) -> Ordering,
712{
713 type Item = W1::Item;
714
715 fn next(&mut self, index: &I) -> Option<Self::Item> {
716 loop {
717 match (self.walk1.peek(index), self.walk2.peek(index)) {
718 (None, _) => {
719 return None;
720 }
721 (_, None) => {
722 return self.walk1.next(index);
723 }
724 (Some(Ok(item1)), Some(Ok(item2))) => match (self.cmp)(item1, item2) {
725 Ordering::Less => {
726 return self.walk1.next(index);
727 }
728 Ordering::Equal => {
729 self.walk2.next(index);
730 self.walk1.next(index);
731 }
732 Ordering::Greater => {
733 self.walk2.next(index);
734 }
735 },
736 (Some(Err(_)), _) => {
737 return self.walk1.next(index);
738 }
739 (_, Some(Err(_))) => {
740 return self.walk2.next(index);
741 }
742 }
743 }
744 }
745}
746
747fn difference_by<I, T, E, W1, W2, C>(
748 walk1: W1,
749 walk2: W2,
750 cmp: C,
751) -> DifferenceRevWalk<I, W1, W2, C>
752where
753 I: ?Sized,
754 W1: RevWalk<I, Item = Result<T, E>>,
755 W2: RevWalk<I, Item = Result<T, E>>,
756 C: FnMut(&T, &T) -> Ordering,
757{
758 DifferenceRevWalk {
759 walk1: walk1.peekable(),
760 walk2: walk2.peekable(),
761 cmp,
762 }
763}
764
765pub fn evaluate<I: AsCompositeIndex + Clone>(
766 expression: &ResolvedExpression,
767 store: &Arc<Store>,
768 index: I,
769) -> Result<RevsetImpl<I>, RevsetEvaluationError> {
770 let context = EvaluationContext {
771 store: store.clone(),
772 index: index.as_composite(),
773 };
774 let internal_revset = context.evaluate(expression)?;
775 Ok(RevsetImpl::new(internal_revset, index))
776}
777
778struct EvaluationContext<'index> {
779 store: Arc<Store>,
780 index: &'index CompositeIndex,
781}
782
783fn to_u32_generation_range(range: &Range<u64>) -> Result<Range<u32>, RevsetEvaluationError> {
784 let start = range.start.try_into().map_err(|_| {
785 RevsetEvaluationError::Other(
786 format!("Lower bound of generation ({}) is too large", range.start).into(),
787 )
788 })?;
789 let end = range.end.try_into().unwrap_or(u32::MAX);
790 Ok(start..end)
791}
792
793impl EvaluationContext<'_> {
794 fn evaluate(
795 &self,
796 expression: &ResolvedExpression,
797 ) -> Result<Box<dyn InternalRevset>, RevsetEvaluationError> {
798 let index = self.index;
799 match expression {
800 ResolvedExpression::Commits(commit_ids) => {
801 Ok(Box::new(self.revset_for_commit_ids(commit_ids)?))
802 }
803 ResolvedExpression::Ancestors { heads, generation } => {
804 let head_set = self.evaluate(heads)?;
805 let head_positions = head_set.positions().attach(index);
806 let builder =
807 RevWalkBuilder::new(index).wanted_heads(head_positions.try_collect()?);
808 if generation == &GENERATION_RANGE_FULL {
809 let walk = builder.ancestors().detach();
810 Ok(Box::new(RevWalkRevset { walk }))
811 } else {
812 let generation = to_u32_generation_range(generation)?;
813 let walk = builder
814 .ancestors_filtered_by_generation(generation)
815 .detach();
816 Ok(Box::new(RevWalkRevset { walk }))
817 }
818 }
819 ResolvedExpression::Range {
820 roots,
821 heads,
822 generation,
823 } => {
824 let root_set = self.evaluate(roots)?;
825 let root_positions: Vec<_> = root_set.positions().attach(index).try_collect()?;
826 let head_set = self.evaluate(heads)?;
830 let head_positions = difference_by(
831 head_set.positions(),
832 EagerRevWalk::new(root_positions.iter().copied().map(Ok)),
833 |pos1, pos2| pos1.cmp(pos2).reverse(),
834 )
835 .attach(index);
836 let builder = RevWalkBuilder::new(index)
837 .wanted_heads(head_positions.try_collect()?)
838 .unwanted_roots(root_positions);
839 if generation == &GENERATION_RANGE_FULL {
840 let walk = builder.ancestors().detach();
841 Ok(Box::new(RevWalkRevset { walk }))
842 } else {
843 let generation = to_u32_generation_range(generation)?;
844 let walk = builder
845 .ancestors_filtered_by_generation(generation)
846 .detach();
847 Ok(Box::new(RevWalkRevset { walk }))
848 }
849 }
850 ResolvedExpression::DagRange {
851 roots,
852 heads,
853 generation_from_roots,
854 } => {
855 let root_set = self.evaluate(roots)?;
856 let root_positions = root_set.positions().attach(index);
857 let head_set = self.evaluate(heads)?;
858 let head_positions = head_set.positions().attach(index);
859 let builder =
860 RevWalkBuilder::new(index).wanted_heads(head_positions.try_collect()?);
861 if generation_from_roots == &(1..2) {
862 let root_positions: HashSet<_> = root_positions.try_collect()?;
863 let walk = builder
864 .ancestors_until_roots(root_positions.iter().copied())
865 .detach();
866 let candidates = RevWalkRevset { walk };
867 let predicate = as_pure_predicate_fn(move |index, pos| {
868 Ok(index
869 .entry_by_pos(pos)
870 .parent_positions()
871 .iter()
872 .any(|parent_pos| root_positions.contains(parent_pos)))
873 });
874 Ok(Box::new(FilterRevset {
877 candidates,
878 predicate,
879 }))
880 } else if generation_from_roots == &GENERATION_RANGE_FULL {
881 let mut positions = builder
882 .descendants(root_positions.try_collect()?)
883 .collect_vec();
884 positions.reverse();
885 Ok(Box::new(EagerRevset { positions }))
886 } else {
887 let mut positions = builder
891 .descendants_filtered_by_generation(
892 root_positions.try_collect()?,
893 to_u32_generation_range(generation_from_roots)?,
894 )
895 .map(|Reverse(pos)| pos)
896 .collect_vec();
897 positions.reverse();
898 Ok(Box::new(EagerRevset { positions }))
899 }
900 }
901 ResolvedExpression::Reachable { sources, domain } => {
902 let mut sets = union_find::UnionFind::<IndexPosition>::new();
903
904 let domain_revset = self.evaluate(domain)?;
906 let domain_vec: Vec<_> = domain_revset.positions().attach(index).try_collect()?;
907 let domain_set: HashSet<_> = domain_vec.iter().copied().collect();
908 for pos in &domain_set {
909 for parent_pos in index.entry_by_pos(*pos).parent_positions() {
910 if domain_set.contains(&parent_pos) {
911 sets.union(*pos, parent_pos);
912 }
913 }
914 }
915
916 let set_reps: HashSet<_> = intersection_by(
918 self.evaluate(sources)?.positions(),
919 EagerRevWalk::new(domain_vec.iter().copied().map(Ok)),
920 |pos1, pos2| pos1.cmp(pos2).reverse(),
921 )
922 .attach(index)
923 .map_ok(|pos| sets.find(pos))
924 .try_collect()?;
925
926 let positions = domain_vec
927 .into_iter()
928 .filter(|pos| set_reps.contains(&sets.find(*pos)))
929 .collect_vec();
930 Ok(Box::new(EagerRevset { positions }))
931 }
932 ResolvedExpression::Heads(candidates) => {
933 let candidate_set = self.evaluate(candidates)?;
934 let head_positions: BTreeSet<_> =
935 index.heads_pos(candidate_set.positions().attach(index).try_collect()?);
936 let positions = head_positions.into_iter().rev().collect();
937 Ok(Box::new(EagerRevset { positions }))
938 }
939 ResolvedExpression::Roots(candidates) => {
940 let mut positions: Vec<_> = self
941 .evaluate(candidates)?
942 .positions()
943 .attach(index)
944 .try_collect()?;
945 let filled = RevWalkBuilder::new(index)
946 .wanted_heads(positions.clone())
947 .descendants(positions.iter().copied().collect())
948 .collect_positions_set();
949 positions.retain(|&pos| {
950 !index
951 .entry_by_pos(pos)
952 .parent_positions()
953 .iter()
954 .any(|parent| filled.contains(parent))
955 });
956 Ok(Box::new(EagerRevset { positions }))
957 }
958 ResolvedExpression::ForkPoint(expression) => {
959 let expression_set = self.evaluate(expression)?;
960 let mut expression_positions_iter = expression_set.positions().attach(index);
961 let Some(position) = expression_positions_iter.next() else {
962 return Ok(Box::new(EagerRevset::empty()));
963 };
964 let mut positions = vec![position?];
965 for position in expression_positions_iter {
966 positions = index
967 .common_ancestors_pos(&positions, [position?].as_slice())
968 .into_iter()
969 .collect_vec();
970 }
971 positions.reverse();
972 Ok(Box::new(EagerRevset { positions }))
973 }
974 ResolvedExpression::Latest { candidates, count } => {
975 let candidate_set = self.evaluate(candidates)?;
976 Ok(Box::new(self.take_latest_revset(&*candidate_set, *count)?))
977 }
978 ResolvedExpression::Coalesce(expression1, expression2) => {
979 let set1 = self.evaluate(expression1)?;
980 if set1.positions().attach(index).next().is_some() {
981 Ok(set1)
982 } else {
983 self.evaluate(expression2)
984 }
985 }
986 ResolvedExpression::Union(expression1, expression2) => {
987 let set1 = self.evaluate(expression1)?;
988 let set2 = self.evaluate(expression2)?;
989 Ok(Box::new(UnionRevset { set1, set2 }))
990 }
991 ResolvedExpression::FilterWithin {
992 candidates,
993 predicate,
994 } => Ok(Box::new(FilterRevset {
995 candidates: self.evaluate(candidates)?,
996 predicate: self.evaluate_predicate(predicate)?,
997 })),
998 ResolvedExpression::Intersection(expression1, expression2) => {
999 let set1 = self.evaluate(expression1)?;
1000 let set2 = self.evaluate(expression2)?;
1001 Ok(Box::new(IntersectionRevset { set1, set2 }))
1002 }
1003 ResolvedExpression::Difference(expression1, expression2) => {
1004 let set1 = self.evaluate(expression1)?;
1005 let set2 = self.evaluate(expression2)?;
1006 Ok(Box::new(DifferenceRevset { set1, set2 }))
1007 }
1008 }
1009 }
1010
1011 fn evaluate_predicate(
1012 &self,
1013 expression: &ResolvedPredicateExpression,
1014 ) -> Result<Box<dyn ToPredicateFn>, RevsetEvaluationError> {
1015 match expression {
1016 ResolvedPredicateExpression::Filter(predicate) => {
1017 Ok(build_predicate_fn(self.store.clone(), predicate))
1018 }
1019 ResolvedPredicateExpression::Set(expression) => {
1020 Ok(self.evaluate(expression)?.into_predicate())
1021 }
1022 ResolvedPredicateExpression::NotIn(complement) => {
1023 let set = self.evaluate_predicate(complement)?;
1024 Ok(Box::new(NotInPredicate(set)))
1025 }
1026 ResolvedPredicateExpression::Union(expression1, expression2) => {
1027 let set1 = self.evaluate_predicate(expression1)?;
1028 let set2 = self.evaluate_predicate(expression2)?;
1029 Ok(Box::new(UnionRevset { set1, set2 }))
1030 }
1031 }
1032 }
1033
1034 fn revset_for_commit_ids(
1035 &self,
1036 commit_ids: &[CommitId],
1037 ) -> Result<EagerRevset, RevsetEvaluationError> {
1038 let mut positions: Vec<_> = commit_ids
1039 .iter()
1040 .map(|id| {
1041 self.index.commit_id_to_pos(id).ok_or_else(|| {
1046 RevsetEvaluationError::Other(
1047 format!(
1048 "Commit ID {} not found in index (index or view might be corrupted)",
1049 id.hex()
1050 )
1051 .into(),
1052 )
1053 })
1054 })
1055 .try_collect()?;
1056 positions.sort_unstable_by_key(|&pos| Reverse(pos));
1057 positions.dedup();
1058 Ok(EagerRevset { positions })
1059 }
1060
1061 fn take_latest_revset(
1062 &self,
1063 candidate_set: &dyn InternalRevset,
1064 count: usize,
1065 ) -> Result<EagerRevset, RevsetEvaluationError> {
1066 if count == 0 {
1067 return Ok(EagerRevset::empty());
1068 }
1069
1070 #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
1071 struct Item {
1072 timestamp: MillisSinceEpoch,
1073 pos: IndexPosition, }
1075
1076 let make_rev_item = |pos| -> Result<_, RevsetEvaluationError> {
1077 let entry = self.index.entry_by_pos(pos?);
1078 let commit = self.store.get_commit(&entry.commit_id())?;
1079 Ok(Reverse(Item {
1080 timestamp: commit.committer().timestamp.timestamp,
1081 pos: entry.position(),
1082 }))
1083 };
1084
1085 let mut candidate_iter = candidate_set
1089 .positions()
1090 .attach(self.index)
1091 .map(make_rev_item)
1092 .fuse();
1093 let mut latest_items: BinaryHeap<_> = candidate_iter.by_ref().take(count).try_collect()?;
1094 for item in candidate_iter {
1095 let item = item?;
1096 let mut earliest = latest_items.peek_mut().unwrap();
1097 if earliest.0 < item.0 {
1098 *earliest = item;
1099 }
1100 }
1101
1102 assert!(latest_items.len() <= count);
1103 let mut positions = latest_items
1104 .into_iter()
1105 .map(|item| item.0.pos)
1106 .collect_vec();
1107 positions.sort_unstable_by_key(|&pos| Reverse(pos));
1108 Ok(EagerRevset { positions })
1109 }
1110}
1111
1112struct PurePredicateFn<F>(F);
1113
1114impl<F> fmt::Debug for PurePredicateFn<F> {
1115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1116 f.debug_struct("PurePredicateFn").finish_non_exhaustive()
1117 }
1118}
1119
1120impl<F> ToPredicateFn for PurePredicateFn<F>
1121where
1122 F: Fn(&CompositeIndex, IndexPosition) -> Result<bool, RevsetEvaluationError> + Clone,
1123{
1124 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
1125 where
1126 Self: 'a,
1127 {
1128 Box::new(self.0.clone())
1129 }
1130}
1131
1132fn as_pure_predicate_fn<F>(f: F) -> PurePredicateFn<F>
1133where
1134 F: Fn(&CompositeIndex, IndexPosition) -> Result<bool, RevsetEvaluationError> + Clone,
1135{
1136 PurePredicateFn(f)
1137}
1138
1139fn box_pure_predicate_fn<'a>(
1140 f: impl Fn(&CompositeIndex, IndexPosition) -> Result<bool, RevsetEvaluationError> + Clone + 'a,
1141) -> Box<dyn ToPredicateFn + 'a> {
1142 Box::new(PurePredicateFn(f))
1143}
1144
1145fn build_predicate_fn(
1146 store: Arc<Store>,
1147 predicate: &RevsetFilterPredicate,
1148) -> Box<dyn ToPredicateFn> {
1149 match predicate {
1150 RevsetFilterPredicate::ParentCount(parent_count_range) => {
1151 let parent_count_range = parent_count_range.clone();
1152 box_pure_predicate_fn(move |index, pos| {
1153 let entry = index.entry_by_pos(pos);
1154 Ok(parent_count_range.contains(&entry.num_parents()))
1155 })
1156 }
1157 RevsetFilterPredicate::Description(pattern) => {
1158 let pattern = pattern.clone();
1159 box_pure_predicate_fn(move |index, pos| {
1160 let entry = index.entry_by_pos(pos);
1161 let commit = store.get_commit(&entry.commit_id())?;
1162 Ok(pattern.matches(commit.description()))
1163 })
1164 }
1165 RevsetFilterPredicate::Subject(pattern) => {
1166 let pattern = pattern.clone();
1167 box_pure_predicate_fn(move |index, pos| {
1168 let entry = index.entry_by_pos(pos);
1169 let commit = store.get_commit(&entry.commit_id())?;
1170 Ok(pattern.matches(commit.description().lines().next().unwrap_or_default()))
1171 })
1172 }
1173 RevsetFilterPredicate::AuthorName(pattern) => {
1174 let pattern = pattern.clone();
1175 box_pure_predicate_fn(move |index, pos| {
1176 let entry = index.entry_by_pos(pos);
1177 let commit = store.get_commit(&entry.commit_id())?;
1178 Ok(pattern.matches(&commit.author().name))
1179 })
1180 }
1181 RevsetFilterPredicate::AuthorEmail(pattern) => {
1182 let pattern = pattern.clone();
1183 box_pure_predicate_fn(move |index, pos| {
1184 let entry = index.entry_by_pos(pos);
1185 let commit = store.get_commit(&entry.commit_id())?;
1186 Ok(pattern.matches(&commit.author().email))
1187 })
1188 }
1189 RevsetFilterPredicate::AuthorDate(expression) => {
1190 let expression = *expression;
1191 box_pure_predicate_fn(move |index, pos| {
1192 let entry = index.entry_by_pos(pos);
1193 let commit = store.get_commit(&entry.commit_id())?;
1194 let author_date = &commit.author().timestamp;
1195 Ok(expression.matches(author_date))
1196 })
1197 }
1198 RevsetFilterPredicate::CommitterName(pattern) => {
1199 let pattern = pattern.clone();
1200 box_pure_predicate_fn(move |index, pos| {
1201 let entry = index.entry_by_pos(pos);
1202 let commit = store.get_commit(&entry.commit_id())?;
1203 Ok(pattern.matches(&commit.committer().name))
1204 })
1205 }
1206 RevsetFilterPredicate::CommitterEmail(pattern) => {
1207 let pattern = pattern.clone();
1208 box_pure_predicate_fn(move |index, pos| {
1209 let entry = index.entry_by_pos(pos);
1210 let commit = store.get_commit(&entry.commit_id())?;
1211 Ok(pattern.matches(&commit.committer().email))
1212 })
1213 }
1214 RevsetFilterPredicate::CommitterDate(expression) => {
1215 let expression = *expression;
1216 box_pure_predicate_fn(move |index, pos| {
1217 let entry = index.entry_by_pos(pos);
1218 let commit = store.get_commit(&entry.commit_id())?;
1219 let committer_date = &commit.committer().timestamp;
1220 Ok(expression.matches(committer_date))
1221 })
1222 }
1223 RevsetFilterPredicate::File(expr) => {
1224 let matcher: Rc<dyn Matcher> = expr.to_matcher().into();
1225 box_pure_predicate_fn(move |index, pos| {
1226 let entry = index.entry_by_pos(pos);
1227 let commit = store.get_commit(&entry.commit_id())?;
1228 Ok(has_diff_from_parent(&store, index, &commit, &*matcher)?)
1229 })
1230 }
1231 RevsetFilterPredicate::DiffContains { text, files } => {
1232 let text_pattern = text.clone();
1233 let files_matcher: Rc<dyn Matcher> = files.to_matcher().into();
1234 box_pure_predicate_fn(move |index, pos| {
1235 let entry = index.entry_by_pos(pos);
1236 let commit = store.get_commit(&entry.commit_id())?;
1237 Ok(matches_diff_from_parent(
1238 &store,
1239 index,
1240 &commit,
1241 &text_pattern,
1242 &*files_matcher,
1243 )?)
1244 })
1245 }
1246 RevsetFilterPredicate::HasConflict => box_pure_predicate_fn(move |index, pos| {
1247 let entry = index.entry_by_pos(pos);
1248 let commit = store.get_commit(&entry.commit_id())?;
1249 Ok(commit.has_conflict()?)
1250 }),
1251 RevsetFilterPredicate::Extension(ext) => {
1252 let ext = ext.clone();
1253 box_pure_predicate_fn(move |index, pos| {
1254 let entry = index.entry_by_pos(pos);
1255 let commit = store.get_commit(&entry.commit_id())?;
1256 Ok(ext.matches_commit(&commit))
1257 })
1258 }
1259 }
1260}
1261
1262fn has_diff_from_parent(
1263 store: &Arc<Store>,
1264 index: &CompositeIndex,
1265 commit: &Commit,
1266 matcher: &dyn Matcher,
1267) -> BackendResult<bool> {
1268 let parents: Vec<_> = commit.parents().try_collect()?;
1269 if let [parent] = parents.as_slice() {
1270 let unchanged = commit.tree_id() == parent.tree_id();
1272 if matcher.visit(RepoPath::root()) == Visit::AllRecursively {
1273 return Ok(!unchanged);
1274 } else if unchanged {
1275 return Ok(false);
1276 }
1277 }
1278
1279 let from_tree = rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?;
1281 let to_tree = commit.tree()?;
1282 let mut tree_diff = from_tree.diff_stream(&to_tree, matcher);
1284 async {
1285 while let Some(entry) = tree_diff.next().await {
1287 let (from_value, to_value) = entry.values?;
1288 let from_value = resolve_file_values(store, &entry.path, from_value).await?;
1289 if from_value == to_value {
1290 continue;
1291 }
1292 return Ok(true);
1293 }
1294 Ok(false)
1295 }
1296 .block_on()
1297}
1298
1299fn matches_diff_from_parent(
1300 store: &Arc<Store>,
1301 index: &CompositeIndex,
1302 commit: &Commit,
1303 text_pattern: &StringPattern,
1304 files_matcher: &dyn Matcher,
1305) -> BackendResult<bool> {
1306 let parents: Vec<_> = commit.parents().try_collect()?;
1307 let from_tree = rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?;
1309 let to_tree = commit.tree()?;
1310 let mut tree_diff = from_tree.diff_stream(&to_tree, files_matcher);
1312 async {
1313 while let Some(entry) = tree_diff.next().await {
1315 let (left_value, right_value) = entry.values?;
1316 let left_value = resolve_file_values(store, &entry.path, left_value).await?;
1317 if left_value == right_value {
1318 continue;
1319 }
1320 let left_future = materialize_tree_value(store, &entry.path, left_value);
1323 let right_future = materialize_tree_value(store, &entry.path, right_value);
1324 let (left_value, right_value) = futures::try_join!(left_future, right_future)?;
1325 let left_content = to_file_content(&entry.path, left_value)?;
1326 let right_content = to_file_content(&entry.path, right_value)?;
1327 let left_lines = match_lines(&left_content, text_pattern);
1330 let right_lines = match_lines(&right_content, text_pattern);
1331 if left_lines.ne(right_lines) {
1332 return Ok(true);
1333 }
1334 }
1335 Ok(false)
1336 }
1337 .block_on()
1338}
1339
1340fn match_lines<'a, 'b>(
1341 text: &'a [u8],
1342 pattern: &'b StringPattern,
1343) -> impl Iterator<Item = &'a [u8]> + use<'a, 'b> {
1344 text.split_inclusive(|b| *b == b'\n').filter(|line| {
1347 let line = line.strip_suffix(b"\n").unwrap_or(line);
1348 str::from_utf8(line).is_ok_and(|line| pattern.matches(line))
1350 })
1351}
1352
1353fn to_file_content(path: &RepoPath, value: MaterializedTreeValue) -> BackendResult<Vec<u8>> {
1354 match value {
1355 MaterializedTreeValue::Absent => Ok(vec![]),
1356 MaterializedTreeValue::AccessDenied(_) => Ok(vec![]),
1357 MaterializedTreeValue::File(mut file) => file.read_all(path),
1358 MaterializedTreeValue::Symlink { id: _, target } => Ok(target.into_bytes()),
1359 MaterializedTreeValue::GitSubmodule(_) => Ok(vec![]),
1360 MaterializedTreeValue::FileConflict { contents, .. } => {
1361 Ok(materialize_merge_result_to_bytes(&contents, ConflictMarkerStyle::default()).into())
1362 }
1363 MaterializedTreeValue::OtherConflict { .. } => Ok(vec![]),
1364 MaterializedTreeValue::Tree(id) => {
1365 panic!("Unexpected tree with id {id:?} in diff at path {path:?}");
1366 }
1367 }
1368}
1369
1370#[cfg(test)]
1371mod tests {
1372 use super::*;
1373 use crate::default_index::DefaultMutableIndex;
1374
1375 fn change_id_generator() -> impl FnMut() -> ChangeId {
1377 let mut iter = (1_u128..).map(|n| ChangeId::new(n.to_le_bytes().into()));
1378 move || iter.next().unwrap()
1379 }
1380
1381 fn try_collect_vec<T, E>(iter: impl IntoIterator<Item = Result<T, E>>) -> Result<Vec<T>, E> {
1382 iter.into_iter().collect()
1383 }
1384
1385 #[test]
1386 fn test_revset_combinator() {
1387 let mut new_change_id = change_id_generator();
1388 let mut index = DefaultMutableIndex::full(3, 16);
1389 let id_0 = CommitId::from_hex("000000");
1390 let id_1 = CommitId::from_hex("111111");
1391 let id_2 = CommitId::from_hex("222222");
1392 let id_3 = CommitId::from_hex("333333");
1393 let id_4 = CommitId::from_hex("444444");
1394 index.add_commit_data(id_0.clone(), new_change_id(), &[]);
1395 index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
1396 index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
1397 index.add_commit_data(id_3.clone(), new_change_id(), &[id_2.clone()]);
1398 index.add_commit_data(id_4.clone(), new_change_id(), &[id_3.clone()]);
1399
1400 let index = index.as_composite();
1401 let get_pos = |id: &CommitId| index.commit_id_to_pos(id).unwrap();
1402 let make_positions = |ids: &[&CommitId]| ids.iter().copied().map(get_pos).collect_vec();
1403 let make_set = |ids: &[&CommitId]| -> Box<dyn InternalRevset> {
1404 let positions = make_positions(ids);
1405 Box::new(EagerRevset { positions })
1406 };
1407
1408 let set = make_set(&[&id_4, &id_3, &id_2, &id_0]);
1409 let mut p = set.to_predicate_fn();
1410 assert!(p(index, get_pos(&id_4)).unwrap());
1411 assert!(p(index, get_pos(&id_3)).unwrap());
1412 assert!(p(index, get_pos(&id_2)).unwrap());
1413 assert!(!p(index, get_pos(&id_1)).unwrap());
1414 assert!(p(index, get_pos(&id_0)).unwrap());
1415 let mut p = set.to_predicate_fn();
1417 assert!(p(index, get_pos(&id_3)).unwrap());
1418 assert!(!p(index, get_pos(&id_1)).unwrap());
1419 assert!(p(index, get_pos(&id_0)).unwrap());
1420
1421 let set = FilterRevset {
1422 candidates: make_set(&[&id_4, &id_2, &id_0]),
1423 predicate: as_pure_predicate_fn(|index, pos| {
1424 Ok(index.entry_by_pos(pos).commit_id() != id_4)
1425 }),
1426 };
1427 assert_eq!(
1428 try_collect_vec(set.positions().attach(index)).unwrap(),
1429 make_positions(&[&id_2, &id_0])
1430 );
1431 let mut p = set.to_predicate_fn();
1432 assert!(!p(index, get_pos(&id_4)).unwrap());
1433 assert!(!p(index, get_pos(&id_3)).unwrap());
1434 assert!(p(index, get_pos(&id_2)).unwrap());
1435 assert!(!p(index, get_pos(&id_1)).unwrap());
1436 assert!(p(index, get_pos(&id_0)).unwrap());
1437
1438 let set = FilterRevset {
1440 candidates: make_set(&[&id_4, &id_2, &id_0]),
1441 predicate: make_set(&[&id_3, &id_2, &id_1]),
1442 };
1443 assert_eq!(
1444 try_collect_vec(set.positions().attach(index)).unwrap(),
1445 make_positions(&[&id_2])
1446 );
1447 let mut p = set.to_predicate_fn();
1448 assert!(!p(index, get_pos(&id_4)).unwrap());
1449 assert!(!p(index, get_pos(&id_3)).unwrap());
1450 assert!(p(index, get_pos(&id_2)).unwrap());
1451 assert!(!p(index, get_pos(&id_1)).unwrap());
1452 assert!(!p(index, get_pos(&id_0)).unwrap());
1453
1454 let set = UnionRevset {
1455 set1: make_set(&[&id_4, &id_2]),
1456 set2: make_set(&[&id_3, &id_2, &id_1]),
1457 };
1458 assert_eq!(
1459 try_collect_vec(set.positions().attach(index)).unwrap(),
1460 make_positions(&[&id_4, &id_3, &id_2, &id_1])
1461 );
1462 let mut p = set.to_predicate_fn();
1463 assert!(p(index, get_pos(&id_4)).unwrap());
1464 assert!(p(index, get_pos(&id_3)).unwrap());
1465 assert!(p(index, get_pos(&id_2)).unwrap());
1466 assert!(p(index, get_pos(&id_1)).unwrap());
1467 assert!(!p(index, get_pos(&id_0)).unwrap());
1468
1469 let set = IntersectionRevset {
1470 set1: make_set(&[&id_4, &id_2, &id_0]),
1471 set2: make_set(&[&id_3, &id_2, &id_1]),
1472 };
1473 assert_eq!(
1474 try_collect_vec(set.positions().attach(index)).unwrap(),
1475 make_positions(&[&id_2])
1476 );
1477 let mut p = set.to_predicate_fn();
1478 assert!(!p(index, get_pos(&id_4)).unwrap());
1479 assert!(!p(index, get_pos(&id_3)).unwrap());
1480 assert!(p(index, get_pos(&id_2)).unwrap());
1481 assert!(!p(index, get_pos(&id_1)).unwrap());
1482 assert!(!p(index, get_pos(&id_0)).unwrap());
1483
1484 let set = DifferenceRevset {
1485 set1: make_set(&[&id_4, &id_2, &id_0]),
1486 set2: make_set(&[&id_3, &id_2, &id_1]),
1487 };
1488 assert_eq!(
1489 try_collect_vec(set.positions().attach(index)).unwrap(),
1490 make_positions(&[&id_4, &id_0])
1491 );
1492 let mut p = set.to_predicate_fn();
1493 assert!(p(index, get_pos(&id_4)).unwrap());
1494 assert!(!p(index, get_pos(&id_3)).unwrap());
1495 assert!(!p(index, get_pos(&id_2)).unwrap());
1496 assert!(!p(index, get_pos(&id_1)).unwrap());
1497 assert!(p(index, get_pos(&id_0)).unwrap());
1498 }
1499
1500 #[test]
1501 fn test_revset_combinator_error_propagation() {
1502 let mut new_change_id = change_id_generator();
1503 let mut index = DefaultMutableIndex::full(3, 16);
1504 let id_0 = CommitId::from_hex("000000");
1505 let id_1 = CommitId::from_hex("111111");
1506 let id_2 = CommitId::from_hex("222222");
1507 index.add_commit_data(id_0.clone(), new_change_id(), &[]);
1508 index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
1509 index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
1510
1511 let index = index.as_composite();
1512 let get_pos = |id: &CommitId| index.commit_id_to_pos(id).unwrap();
1513 let make_positions = |ids: &[&CommitId]| ids.iter().copied().map(get_pos).collect_vec();
1514 let make_good_set = |ids: &[&CommitId]| -> Box<dyn InternalRevset> {
1515 let positions = make_positions(ids);
1516 Box::new(EagerRevset { positions })
1517 };
1518 let make_bad_set = |ids: &[&CommitId], bad_id: &CommitId| -> Box<dyn InternalRevset> {
1519 let positions = make_positions(ids);
1520 let bad_id = bad_id.clone();
1521 Box::new(FilterRevset {
1522 candidates: EagerRevset { positions },
1523 predicate: as_pure_predicate_fn(move |index, pos| {
1524 if index.entry_by_pos(pos).commit_id() == bad_id {
1525 Err(RevsetEvaluationError::Other("bad".into()))
1526 } else {
1527 Ok(true)
1528 }
1529 }),
1530 })
1531 };
1532
1533 let set = make_bad_set(&[&id_2, &id_1, &id_0], &id_1);
1535 assert_eq!(
1536 try_collect_vec(set.positions().attach(index).take(1)).unwrap(),
1537 make_positions(&[&id_2])
1538 );
1539 assert!(try_collect_vec(set.positions().attach(index).take(2)).is_err());
1540 let mut p = set.to_predicate_fn();
1541 assert!(p(index, get_pos(&id_2)).unwrap());
1542 assert!(p(index, get_pos(&id_1)).is_err());
1543
1544 let set = FilterRevset {
1546 candidates: make_bad_set(&[&id_2, &id_1, &id_0], &id_1),
1547 predicate: as_pure_predicate_fn(|_, _| Ok(true)),
1548 };
1549 assert_eq!(
1550 try_collect_vec(set.positions().attach(index).take(1)).unwrap(),
1551 make_positions(&[&id_2])
1552 );
1553 assert!(try_collect_vec(set.positions().attach(index).take(2)).is_err());
1554 let mut p = set.to_predicate_fn();
1555 assert!(p(index, get_pos(&id_2)).unwrap());
1556 assert!(p(index, get_pos(&id_1)).is_err());
1557
1558 let set = UnionRevset {
1560 set1: make_bad_set(&[&id_1], &id_1),
1561 set2: make_good_set(&[&id_2, &id_1]),
1562 };
1563 assert!(try_collect_vec(set.positions().attach(index).take(1)).is_err());
1564 let mut p = set.to_predicate_fn();
1565 assert!(p(index, get_pos(&id_2)).unwrap()); assert!(p(index, get_pos(&id_1)).is_err());
1567
1568 let set = UnionRevset {
1570 set1: make_good_set(&[&id_2, &id_1]),
1571 set2: make_bad_set(&[&id_1, &id_0], &id_0),
1572 };
1573 assert_eq!(
1574 try_collect_vec(set.positions().attach(index).take(2)).unwrap(),
1575 make_positions(&[&id_2, &id_1])
1576 );
1577 assert!(try_collect_vec(set.positions().attach(index).take(3)).is_err());
1578 let mut p = set.to_predicate_fn();
1579 assert!(p(index, get_pos(&id_2)).unwrap());
1580 assert!(p(index, get_pos(&id_1)).unwrap());
1581 assert!(p(index, get_pos(&id_0)).is_err());
1582
1583 let set = IntersectionRevset {
1585 set1: make_bad_set(&[&id_1], &id_1),
1586 set2: make_good_set(&[&id_2, &id_1]),
1587 };
1588 assert!(try_collect_vec(set.positions().attach(index).take(1)).is_err());
1589 let mut p = set.to_predicate_fn();
1590 assert!(!p(index, get_pos(&id_2)).unwrap());
1591 assert!(p(index, get_pos(&id_1)).is_err());
1592
1593 let set = IntersectionRevset {
1595 set1: make_good_set(&[&id_2, &id_1, &id_0]),
1596 set2: make_bad_set(&[&id_1, &id_0], &id_0),
1597 };
1598 assert_eq!(
1599 try_collect_vec(set.positions().attach(index).take(1)).unwrap(),
1600 make_positions(&[&id_1])
1601 );
1602 assert!(try_collect_vec(set.positions().attach(index).take(2)).is_err());
1603 let mut p = set.to_predicate_fn();
1604 assert!(!p(index, get_pos(&id_2)).unwrap());
1605 assert!(p(index, get_pos(&id_1)).unwrap());
1606 assert!(p(index, get_pos(&id_0)).is_err());
1607
1608 let set = DifferenceRevset {
1610 set1: make_bad_set(&[&id_1], &id_1),
1611 set2: make_good_set(&[&id_2, &id_1]),
1612 };
1613 assert!(try_collect_vec(set.positions().attach(index).take(1)).is_err());
1614 let mut p = set.to_predicate_fn();
1615 assert!(!p(index, get_pos(&id_2)).unwrap());
1616 assert!(p(index, get_pos(&id_1)).is_err());
1617
1618 let set = DifferenceRevset {
1620 set1: make_good_set(&[&id_2, &id_1, &id_0]),
1621 set2: make_bad_set(&[&id_1, &id_0], &id_0),
1622 };
1623 assert_eq!(
1624 try_collect_vec(set.positions().attach(index).take(1)).unwrap(),
1625 make_positions(&[&id_2])
1626 );
1627 assert!(try_collect_vec(set.positions().attach(index).take(2)).is_err());
1628 let mut p = set.to_predicate_fn();
1629 assert!(p(index, get_pos(&id_2)).unwrap());
1630 assert!(!p(index, get_pos(&id_1)).unwrap());
1631 assert!(p(index, get_pos(&id_0)).is_err());
1632 }
1633
1634 #[test]
1635 fn test_positions_accumulator() {
1636 let mut new_change_id = change_id_generator();
1637 let mut index = DefaultMutableIndex::full(3, 16);
1638 let id_0 = CommitId::from_hex("000000");
1639 let id_1 = CommitId::from_hex("111111");
1640 let id_2 = CommitId::from_hex("222222");
1641 let id_3 = CommitId::from_hex("333333");
1642 let id_4 = CommitId::from_hex("444444");
1643 index.add_commit_data(id_0.clone(), new_change_id(), &[]);
1644 index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
1645 index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
1646 index.add_commit_data(id_3.clone(), new_change_id(), &[id_2.clone()]);
1647 index.add_commit_data(id_4.clone(), new_change_id(), &[id_3.clone()]);
1648
1649 let index = index.as_composite();
1650 let get_pos = |id: &CommitId| index.commit_id_to_pos(id).unwrap();
1651 let make_positions = |ids: &[&CommitId]| ids.iter().copied().map(get_pos).collect_vec();
1652 let make_set = |ids: &[&CommitId]| -> Box<dyn InternalRevset> {
1653 let positions = make_positions(ids);
1654 Box::new(EagerRevset { positions })
1655 };
1656
1657 let full_set = make_set(&[&id_4, &id_3, &id_2, &id_1, &id_0]);
1658
1659 let positions_accum = PositionsAccumulator::new(index, full_set.positions());
1661
1662 assert!(positions_accum.contains(&id_3).unwrap());
1663 assert_eq!(positions_accum.consumed_len(), 2);
1664
1665 assert!(positions_accum.contains(&id_0).unwrap());
1666 assert_eq!(positions_accum.consumed_len(), 5);
1667
1668 assert!(positions_accum.contains(&id_3).unwrap());
1669 assert_eq!(positions_accum.consumed_len(), 5);
1670
1671 let positions_accum = PositionsAccumulator::new(index, full_set.positions());
1673
1674 assert!(!positions_accum
1675 .contains(&CommitId::from_hex("999999"))
1676 .unwrap());
1677 assert_eq!(positions_accum.consumed_len(), 0);
1678
1679 let set = make_set(&[&id_3, &id_2, &id_1]);
1681 let positions_accum = PositionsAccumulator::new(index, set.positions());
1682
1683 assert!(!positions_accum.contains(&id_4).unwrap());
1684 assert_eq!(positions_accum.consumed_len(), 1);
1685
1686 assert!(positions_accum.contains(&id_3).unwrap());
1687 assert_eq!(positions_accum.consumed_len(), 1);
1688
1689 assert!(!positions_accum.contains(&id_0).unwrap());
1690 assert_eq!(positions_accum.consumed_len(), 3);
1691
1692 assert!(positions_accum.contains(&id_1).unwrap());
1693 }
1694}