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