1#![allow(missing_docs)]
16
17use std::cell::RefCell;
18use std::cmp::Ordering;
19use std::cmp::Reverse;
20use std::collections::BinaryHeap;
21use std::collections::HashSet;
22use std::convert::Infallible;
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 positions =
938 index.heads_pos(candidate_set.positions().attach(index).try_collect()?);
939 Ok(Box::new(EagerRevset { positions }))
940 }
941 ResolvedExpression::HeadsRange {
942 roots,
943 heads,
944 filter,
945 } => {
946 let root_set = self.evaluate(roots)?;
947 let root_positions: Vec<_> = root_set.positions().attach(index).try_collect()?;
948 let head_set = self.evaluate(heads)?;
952 let head_positions = difference_by(
953 head_set.positions(),
954 EagerRevWalk::new(root_positions.iter().copied().map(Ok)),
955 |pos1, pos2| pos1.cmp(pos2).reverse(),
956 )
957 .attach(index)
958 .try_collect()?;
959 let positions = if let Some(filter) = filter {
960 let mut filter = self.evaluate_predicate(filter)?.to_predicate_fn();
961 index.heads_from_range_and_filter(root_positions, head_positions, |pos| {
962 filter(index, pos)
963 })?
964 } else {
965 let Ok(positions) = index.heads_from_range_and_filter::<Infallible>(
966 root_positions,
967 head_positions,
968 |_| Ok(true),
969 );
970 positions
971 };
972 Ok(Box::new(EagerRevset { positions }))
973 }
974 ResolvedExpression::Roots(candidates) => {
975 let mut positions: Vec<_> = self
976 .evaluate(candidates)?
977 .positions()
978 .attach(index)
979 .try_collect()?;
980 let filled = RevWalkBuilder::new(index)
981 .wanted_heads(positions.clone())
982 .descendants(positions.iter().copied().collect())
983 .collect_positions_set();
984 positions.retain(|&pos| {
985 !index
986 .entry_by_pos(pos)
987 .parent_positions()
988 .iter()
989 .any(|parent| filled.contains(parent))
990 });
991 Ok(Box::new(EagerRevset { positions }))
992 }
993 ResolvedExpression::ForkPoint(expression) => {
994 let expression_set = self.evaluate(expression)?;
995 let mut expression_positions_iter = expression_set.positions().attach(index);
996 let Some(position) = expression_positions_iter.next() else {
997 return Ok(Box::new(EagerRevset::empty()));
998 };
999 let mut positions = vec![position?];
1000 for position in expression_positions_iter {
1001 positions = index.common_ancestors_pos(positions, vec![position?]);
1002 }
1003 Ok(Box::new(EagerRevset { positions }))
1004 }
1005 ResolvedExpression::Latest { candidates, count } => {
1006 let candidate_set = self.evaluate(candidates)?;
1007 Ok(Box::new(self.take_latest_revset(&*candidate_set, *count)?))
1008 }
1009 ResolvedExpression::Coalesce(expression1, expression2) => {
1010 let set1 = self.evaluate(expression1)?;
1011 if set1.positions().attach(index).next().is_some() {
1012 Ok(set1)
1013 } else {
1014 self.evaluate(expression2)
1015 }
1016 }
1017 ResolvedExpression::Union(expression1, expression2) => {
1018 let set1 = self.evaluate(expression1)?;
1019 let set2 = self.evaluate(expression2)?;
1020 Ok(Box::new(UnionRevset { set1, set2 }))
1021 }
1022 ResolvedExpression::FilterWithin {
1023 candidates,
1024 predicate,
1025 } => Ok(Box::new(FilterRevset {
1026 candidates: self.evaluate(candidates)?,
1027 predicate: self.evaluate_predicate(predicate)?,
1028 })),
1029 ResolvedExpression::Intersection(expression1, expression2) => {
1030 let set1 = self.evaluate(expression1)?;
1031 let set2 = self.evaluate(expression2)?;
1032 Ok(Box::new(IntersectionRevset { set1, set2 }))
1033 }
1034 ResolvedExpression::Difference(expression1, expression2) => {
1035 let set1 = self.evaluate(expression1)?;
1036 let set2 = self.evaluate(expression2)?;
1037 Ok(Box::new(DifferenceRevset { set1, set2 }))
1038 }
1039 }
1040 }
1041
1042 fn evaluate_predicate(
1043 &self,
1044 expression: &ResolvedPredicateExpression,
1045 ) -> Result<Box<dyn ToPredicateFn>, RevsetEvaluationError> {
1046 match expression {
1047 ResolvedPredicateExpression::Filter(predicate) => {
1048 Ok(build_predicate_fn(self.store.clone(), predicate))
1049 }
1050 ResolvedPredicateExpression::Set(expression) => {
1051 Ok(self.evaluate(expression)?.into_predicate())
1052 }
1053 ResolvedPredicateExpression::NotIn(complement) => {
1054 let set = self.evaluate_predicate(complement)?;
1055 Ok(Box::new(NotInPredicate(set)))
1056 }
1057 ResolvedPredicateExpression::Union(expression1, expression2) => {
1058 let set1 = self.evaluate_predicate(expression1)?;
1059 let set2 = self.evaluate_predicate(expression2)?;
1060 Ok(Box::new(UnionRevset { set1, set2 }))
1061 }
1062 ResolvedPredicateExpression::Intersection(expression1, expression2) => {
1063 let set1 = self.evaluate_predicate(expression1)?;
1064 let set2 = self.evaluate_predicate(expression2)?;
1065 Ok(Box::new(IntersectionRevset { set1, set2 }))
1066 }
1067 }
1068 }
1069
1070 fn revset_for_commit_ids(
1071 &self,
1072 commit_ids: &[CommitId],
1073 ) -> Result<EagerRevset, RevsetEvaluationError> {
1074 let mut positions: Vec<_> = commit_ids
1075 .iter()
1076 .map(|id| {
1077 self.index.commit_id_to_pos(id).ok_or_else(|| {
1082 RevsetEvaluationError::Other(
1083 format!(
1084 "Commit ID {} not found in index (index or view might be corrupted)",
1085 id.hex()
1086 )
1087 .into(),
1088 )
1089 })
1090 })
1091 .try_collect()?;
1092 positions.sort_unstable_by_key(|&pos| Reverse(pos));
1093 positions.dedup();
1094 Ok(EagerRevset { positions })
1095 }
1096
1097 fn take_latest_revset(
1098 &self,
1099 candidate_set: &dyn InternalRevset,
1100 count: usize,
1101 ) -> Result<EagerRevset, RevsetEvaluationError> {
1102 if count == 0 {
1103 return Ok(EagerRevset::empty());
1104 }
1105
1106 #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
1107 struct Item {
1108 timestamp: MillisSinceEpoch,
1109 pos: IndexPosition, }
1111
1112 let make_rev_item = |pos| -> Result<_, RevsetEvaluationError> {
1113 let entry = self.index.entry_by_pos(pos?);
1114 let commit = self.store.get_commit(&entry.commit_id())?;
1115 Ok(Reverse(Item {
1116 timestamp: commit.committer().timestamp.timestamp,
1117 pos: entry.position(),
1118 }))
1119 };
1120
1121 let mut candidate_iter = candidate_set
1125 .positions()
1126 .attach(self.index)
1127 .map(make_rev_item)
1128 .fuse();
1129 let mut latest_items: BinaryHeap<_> = candidate_iter.by_ref().take(count).try_collect()?;
1130 for item in candidate_iter {
1131 let item = item?;
1132 let mut earliest = latest_items.peek_mut().unwrap();
1133 if earliest.0 < item.0 {
1134 *earliest = item;
1135 }
1136 }
1137
1138 assert!(latest_items.len() <= count);
1139 let mut positions = latest_items
1140 .into_iter()
1141 .map(|item| item.0.pos)
1142 .collect_vec();
1143 positions.sort_unstable_by_key(|&pos| Reverse(pos));
1144 Ok(EagerRevset { positions })
1145 }
1146}
1147
1148struct PurePredicateFn<F>(F);
1149
1150impl<F> fmt::Debug for PurePredicateFn<F> {
1151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1152 f.debug_struct("PurePredicateFn").finish_non_exhaustive()
1153 }
1154}
1155
1156impl<F> ToPredicateFn for PurePredicateFn<F>
1157where
1158 F: Fn(&CompositeIndex, IndexPosition) -> Result<bool, RevsetEvaluationError> + Clone,
1159{
1160 fn to_predicate_fn<'a>(&self) -> BoxedPredicateFn<'a>
1161 where
1162 Self: 'a,
1163 {
1164 Box::new(self.0.clone())
1165 }
1166}
1167
1168fn as_pure_predicate_fn<F>(f: F) -> PurePredicateFn<F>
1169where
1170 F: Fn(&CompositeIndex, IndexPosition) -> Result<bool, RevsetEvaluationError> + Clone,
1171{
1172 PurePredicateFn(f)
1173}
1174
1175fn box_pure_predicate_fn<'a>(
1176 f: impl Fn(&CompositeIndex, IndexPosition) -> Result<bool, RevsetEvaluationError> + Clone + 'a,
1177) -> Box<dyn ToPredicateFn + 'a> {
1178 Box::new(PurePredicateFn(f))
1179}
1180
1181fn build_predicate_fn(
1182 store: Arc<Store>,
1183 predicate: &RevsetFilterPredicate,
1184) -> Box<dyn ToPredicateFn> {
1185 match predicate {
1186 RevsetFilterPredicate::ParentCount(parent_count_range) => {
1187 let parent_count_range = parent_count_range.clone();
1188 box_pure_predicate_fn(move |index, pos| {
1189 let entry = index.entry_by_pos(pos);
1190 Ok(parent_count_range.contains(&entry.num_parents()))
1191 })
1192 }
1193 RevsetFilterPredicate::Description(pattern) => {
1194 let pattern = pattern.clone();
1195 box_pure_predicate_fn(move |index, pos| {
1196 let entry = index.entry_by_pos(pos);
1197 let commit = store.get_commit(&entry.commit_id())?;
1198 Ok(pattern.matches(commit.description()))
1199 })
1200 }
1201 RevsetFilterPredicate::Subject(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.description().lines().next().unwrap_or_default()))
1207 })
1208 }
1209 RevsetFilterPredicate::AuthorName(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.author().name))
1215 })
1216 }
1217 RevsetFilterPredicate::AuthorEmail(pattern) => {
1218 let pattern = pattern.clone();
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 Ok(pattern.matches(&commit.author().email))
1223 })
1224 }
1225 RevsetFilterPredicate::AuthorDate(expression) => {
1226 let expression = *expression;
1227 box_pure_predicate_fn(move |index, pos| {
1228 let entry = index.entry_by_pos(pos);
1229 let commit = store.get_commit(&entry.commit_id())?;
1230 let author_date = &commit.author().timestamp;
1231 Ok(expression.matches(author_date))
1232 })
1233 }
1234 RevsetFilterPredicate::CommitterName(pattern) => {
1235 let pattern = pattern.clone();
1236 box_pure_predicate_fn(move |index, pos| {
1237 let entry = index.entry_by_pos(pos);
1238 let commit = store.get_commit(&entry.commit_id())?;
1239 Ok(pattern.matches(&commit.committer().name))
1240 })
1241 }
1242 RevsetFilterPredicate::CommitterEmail(pattern) => {
1243 let pattern = pattern.clone();
1244 box_pure_predicate_fn(move |index, pos| {
1245 let entry = index.entry_by_pos(pos);
1246 let commit = store.get_commit(&entry.commit_id())?;
1247 Ok(pattern.matches(&commit.committer().email))
1248 })
1249 }
1250 RevsetFilterPredicate::CommitterDate(expression) => {
1251 let expression = *expression;
1252 box_pure_predicate_fn(move |index, pos| {
1253 let entry = index.entry_by_pos(pos);
1254 let commit = store.get_commit(&entry.commit_id())?;
1255 let committer_date = &commit.committer().timestamp;
1256 Ok(expression.matches(committer_date))
1257 })
1258 }
1259 RevsetFilterPredicate::File(expr) => {
1260 let matcher: Rc<dyn Matcher> = expr.to_matcher().into();
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(has_diff_from_parent(&store, index, &commit, &*matcher).block_on()?)
1265 })
1266 }
1267 RevsetFilterPredicate::DiffContains { text, files } => {
1268 let text_pattern = text.clone();
1269 let files_matcher: Rc<dyn Matcher> = files.to_matcher().into();
1270 box_pure_predicate_fn(move |index, pos| {
1271 let entry = index.entry_by_pos(pos);
1272 let commit = store.get_commit(&entry.commit_id())?;
1273 Ok(
1274 matches_diff_from_parent(
1275 &store,
1276 index,
1277 &commit,
1278 &text_pattern,
1279 &*files_matcher,
1280 )
1281 .block_on()?,
1282 )
1283 })
1284 }
1285 RevsetFilterPredicate::HasConflict => box_pure_predicate_fn(move |index, pos| {
1286 let entry = index.entry_by_pos(pos);
1287 let commit = store.get_commit(&entry.commit_id())?;
1288 Ok(commit.has_conflict()?)
1289 }),
1290 RevsetFilterPredicate::Signed => box_pure_predicate_fn(move |index, pos| {
1291 let entry = index.entry_by_pos(pos);
1292 let commit = store.get_commit(&entry.commit_id())?;
1293 Ok(commit.is_signed())
1294 }),
1295 RevsetFilterPredicate::Extension(ext) => {
1296 let ext = ext.clone();
1297 box_pure_predicate_fn(move |index, pos| {
1298 let entry = index.entry_by_pos(pos);
1299 let commit = store.get_commit(&entry.commit_id())?;
1300 Ok(ext.matches_commit(&commit))
1301 })
1302 }
1303 }
1304}
1305
1306async fn has_diff_from_parent(
1307 store: &Arc<Store>,
1308 index: &CompositeIndex,
1309 commit: &Commit,
1310 matcher: &dyn Matcher,
1311) -> BackendResult<bool> {
1312 let parents: Vec<_> = commit.parents().try_collect()?;
1313 if let [parent] = parents.as_slice() {
1314 let unchanged = commit.tree_id() == parent.tree_id();
1316 if matcher.visit(RepoPath::root()) == Visit::AllRecursively {
1317 return Ok(!unchanged);
1318 } else if unchanged {
1319 return Ok(false);
1320 }
1321 }
1322
1323 let from_tree = rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?;
1325 let to_tree = commit.tree()?;
1326 let mut tree_diff = from_tree.diff_stream(&to_tree, matcher);
1328 while let Some(entry) = tree_diff.next().await {
1330 let (from_value, to_value) = entry.values?;
1331 let from_value = resolve_file_values(store, &entry.path, from_value).await?;
1332 if from_value == to_value {
1333 continue;
1334 }
1335 return Ok(true);
1336 }
1337 Ok(false)
1338}
1339
1340async fn matches_diff_from_parent(
1341 store: &Arc<Store>,
1342 index: &CompositeIndex,
1343 commit: &Commit,
1344 text_pattern: &StringPattern,
1345 files_matcher: &dyn Matcher,
1346) -> BackendResult<bool> {
1347 let parents: Vec<_> = commit.parents().try_collect()?;
1348 let from_tree = rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?;
1350 let to_tree = commit.tree()?;
1351 let mut tree_diff = from_tree.diff_stream(&to_tree, files_matcher);
1353 while let Some(entry) = tree_diff.next().await {
1355 let (left_value, right_value) = entry.values?;
1356 let left_value = resolve_file_values(store, &entry.path, left_value).await?;
1357 if left_value == right_value {
1358 continue;
1359 }
1360 let left_future = materialize_tree_value(store, &entry.path, left_value);
1361 let right_future = materialize_tree_value(store, &entry.path, right_value);
1362 let (left_value, right_value) = futures::try_join!(left_future, right_future)?;
1363 let left_contents = to_file_content(&entry.path, left_value).await?;
1364 let right_contents = to_file_content(&entry.path, right_value).await?;
1365 if diff_match_lines(&left_contents, &right_contents, text_pattern)? {
1366 return Ok(true);
1367 }
1368 }
1369 Ok(false)
1370}
1371
1372fn diff_match_lines(
1373 lefts: &Merge<BString>,
1374 rights: &Merge<BString>,
1375 pattern: &StringPattern,
1376) -> BackendResult<bool> {
1377 if let (Some(left), Some(right)) = (lefts.as_resolved(), rights.as_resolved()) {
1380 let left_lines = match_lines(left, pattern);
1381 let right_lines = match_lines(right, pattern);
1382 Ok(left_lines.ne(right_lines))
1383 } else {
1384 let lefts: Merge<BString> = lefts.map(|text| match_lines(text, pattern).collect());
1385 let rights: Merge<BString> = rights.map(|text| match_lines(text, pattern).collect());
1386 let lefts = files::merge(&lefts);
1387 let rights = files::merge(&rights);
1388 let diff = Diff::by_line(lefts.iter().chain(rights.iter()));
1389 let different = files::conflict_diff_hunks(diff.hunks(), lefts.as_slice().len())
1390 .any(|hunk| hunk.kind == DiffHunkKind::Different);
1391 Ok(different)
1392 }
1393}
1394
1395fn match_lines<'a, 'b>(
1396 text: &'a [u8],
1397 pattern: &'b StringPattern,
1398) -> impl Iterator<Item = &'a [u8]> + use<'a, 'b> {
1399 text.split_inclusive(|b| *b == b'\n').filter(|line| {
1402 let line = line.strip_suffix(b"\n").unwrap_or(line);
1403 str::from_utf8(line).is_ok_and(|line| pattern.matches(line))
1405 })
1406}
1407
1408async fn to_file_content(
1409 path: &RepoPath,
1410 value: MaterializedTreeValue,
1411) -> BackendResult<Merge<BString>> {
1412 let empty = || Merge::resolved(BString::default());
1413 match value {
1414 MaterializedTreeValue::Absent => Ok(empty()),
1415 MaterializedTreeValue::AccessDenied(_) => Ok(empty()),
1416 MaterializedTreeValue::File(mut file) => {
1417 Ok(Merge::resolved(file.read_all(path).await?.into()))
1418 }
1419 MaterializedTreeValue::Symlink { id: _, target } => Ok(Merge::resolved(target.into())),
1420 MaterializedTreeValue::GitSubmodule(_) => Ok(empty()),
1421 MaterializedTreeValue::FileConflict(file) => Ok(file.contents),
1422 MaterializedTreeValue::OtherConflict { .. } => Ok(empty()),
1423 MaterializedTreeValue::Tree(id) => {
1424 panic!("Unexpected tree with id {id:?} in diff at path {path:?}");
1425 }
1426 }
1427}
1428
1429#[cfg(test)]
1430#[rustversion::attr(
1431 since(1.89),
1432 expect(clippy::cloned_ref_to_slice_refs, reason = "makes tests more readable")
1433)]
1434mod tests {
1435 use indoc::indoc;
1436
1437 use super::*;
1438 use crate::default_index::DefaultMutableIndex;
1439
1440 fn change_id_generator() -> impl FnMut() -> ChangeId {
1442 let mut iter = (1_u128..).map(|n| ChangeId::new(n.to_le_bytes().into()));
1443 move || iter.next().unwrap()
1444 }
1445
1446 fn try_collect_vec<T, E>(iter: impl IntoIterator<Item = Result<T, E>>) -> Result<Vec<T>, E> {
1447 iter.into_iter().collect()
1448 }
1449
1450 #[test]
1451 fn test_revset_combinator() {
1452 let mut new_change_id = change_id_generator();
1453 let mut index = DefaultMutableIndex::full(3, 16);
1454 let id_0 = CommitId::from_hex("000000");
1455 let id_1 = CommitId::from_hex("111111");
1456 let id_2 = CommitId::from_hex("222222");
1457 let id_3 = CommitId::from_hex("333333");
1458 let id_4 = CommitId::from_hex("444444");
1459 index.add_commit_data(id_0.clone(), new_change_id(), &[]);
1460 index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
1461 index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
1462 index.add_commit_data(id_3.clone(), new_change_id(), &[id_2.clone()]);
1463 index.add_commit_data(id_4.clone(), new_change_id(), &[id_3.clone()]);
1464
1465 let index = index.as_composite();
1466 let get_pos = |id: &CommitId| index.commit_id_to_pos(id).unwrap();
1467 let make_positions = |ids: &[&CommitId]| ids.iter().copied().map(get_pos).collect_vec();
1468 let make_set = |ids: &[&CommitId]| -> Box<dyn InternalRevset> {
1469 let positions = make_positions(ids);
1470 Box::new(EagerRevset { positions })
1471 };
1472
1473 let set = make_set(&[&id_4, &id_3, &id_2, &id_0]);
1474 let mut p = set.to_predicate_fn();
1475 assert!(p(index, get_pos(&id_4)).unwrap());
1476 assert!(p(index, get_pos(&id_3)).unwrap());
1477 assert!(p(index, get_pos(&id_2)).unwrap());
1478 assert!(!p(index, get_pos(&id_1)).unwrap());
1479 assert!(p(index, get_pos(&id_0)).unwrap());
1480 let mut p = set.to_predicate_fn();
1482 assert!(p(index, get_pos(&id_3)).unwrap());
1483 assert!(!p(index, get_pos(&id_1)).unwrap());
1484 assert!(p(index, get_pos(&id_0)).unwrap());
1485
1486 let set = FilterRevset {
1487 candidates: make_set(&[&id_4, &id_2, &id_0]),
1488 predicate: as_pure_predicate_fn(|index, pos| {
1489 Ok(index.entry_by_pos(pos).commit_id() != id_4)
1490 }),
1491 };
1492 assert_eq!(
1493 try_collect_vec(set.positions().attach(index)).unwrap(),
1494 make_positions(&[&id_2, &id_0])
1495 );
1496 let mut p = set.to_predicate_fn();
1497 assert!(!p(index, get_pos(&id_4)).unwrap());
1498 assert!(!p(index, get_pos(&id_3)).unwrap());
1499 assert!(p(index, get_pos(&id_2)).unwrap());
1500 assert!(!p(index, get_pos(&id_1)).unwrap());
1501 assert!(p(index, get_pos(&id_0)).unwrap());
1502
1503 let set = FilterRevset {
1505 candidates: make_set(&[&id_4, &id_2, &id_0]),
1506 predicate: make_set(&[&id_3, &id_2, &id_1]),
1507 };
1508 assert_eq!(
1509 try_collect_vec(set.positions().attach(index)).unwrap(),
1510 make_positions(&[&id_2])
1511 );
1512 let mut p = set.to_predicate_fn();
1513 assert!(!p(index, get_pos(&id_4)).unwrap());
1514 assert!(!p(index, get_pos(&id_3)).unwrap());
1515 assert!(p(index, get_pos(&id_2)).unwrap());
1516 assert!(!p(index, get_pos(&id_1)).unwrap());
1517 assert!(!p(index, get_pos(&id_0)).unwrap());
1518
1519 let set = UnionRevset {
1520 set1: make_set(&[&id_4, &id_2]),
1521 set2: make_set(&[&id_3, &id_2, &id_1]),
1522 };
1523 assert_eq!(
1524 try_collect_vec(set.positions().attach(index)).unwrap(),
1525 make_positions(&[&id_4, &id_3, &id_2, &id_1])
1526 );
1527 let mut p = set.to_predicate_fn();
1528 assert!(p(index, get_pos(&id_4)).unwrap());
1529 assert!(p(index, get_pos(&id_3)).unwrap());
1530 assert!(p(index, get_pos(&id_2)).unwrap());
1531 assert!(p(index, get_pos(&id_1)).unwrap());
1532 assert!(!p(index, get_pos(&id_0)).unwrap());
1533
1534 let set = IntersectionRevset {
1535 set1: make_set(&[&id_4, &id_2, &id_0]),
1536 set2: make_set(&[&id_3, &id_2, &id_1]),
1537 };
1538 assert_eq!(
1539 try_collect_vec(set.positions().attach(index)).unwrap(),
1540 make_positions(&[&id_2])
1541 );
1542 let mut p = set.to_predicate_fn();
1543 assert!(!p(index, get_pos(&id_4)).unwrap());
1544 assert!(!p(index, get_pos(&id_3)).unwrap());
1545 assert!(p(index, get_pos(&id_2)).unwrap());
1546 assert!(!p(index, get_pos(&id_1)).unwrap());
1547 assert!(!p(index, get_pos(&id_0)).unwrap());
1548
1549 let set = DifferenceRevset {
1550 set1: make_set(&[&id_4, &id_2, &id_0]),
1551 set2: make_set(&[&id_3, &id_2, &id_1]),
1552 };
1553 assert_eq!(
1554 try_collect_vec(set.positions().attach(index)).unwrap(),
1555 make_positions(&[&id_4, &id_0])
1556 );
1557 let mut p = set.to_predicate_fn();
1558 assert!(p(index, get_pos(&id_4)).unwrap());
1559 assert!(!p(index, get_pos(&id_3)).unwrap());
1560 assert!(!p(index, get_pos(&id_2)).unwrap());
1561 assert!(!p(index, get_pos(&id_1)).unwrap());
1562 assert!(p(index, get_pos(&id_0)).unwrap());
1563 }
1564
1565 #[test]
1566 fn test_revset_combinator_error_propagation() {
1567 let mut new_change_id = change_id_generator();
1568 let mut index = DefaultMutableIndex::full(3, 16);
1569 let id_0 = CommitId::from_hex("000000");
1570 let id_1 = CommitId::from_hex("111111");
1571 let id_2 = CommitId::from_hex("222222");
1572 index.add_commit_data(id_0.clone(), new_change_id(), &[]);
1573 index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
1574 index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
1575
1576 let index = index.as_composite();
1577 let get_pos = |id: &CommitId| index.commit_id_to_pos(id).unwrap();
1578 let make_positions = |ids: &[&CommitId]| ids.iter().copied().map(get_pos).collect_vec();
1579 let make_good_set = |ids: &[&CommitId]| -> Box<dyn InternalRevset> {
1580 let positions = make_positions(ids);
1581 Box::new(EagerRevset { positions })
1582 };
1583 let make_bad_set = |ids: &[&CommitId], bad_id: &CommitId| -> Box<dyn InternalRevset> {
1584 let positions = make_positions(ids);
1585 let bad_id = bad_id.clone();
1586 Box::new(FilterRevset {
1587 candidates: EagerRevset { positions },
1588 predicate: as_pure_predicate_fn(move |index, pos| {
1589 if index.entry_by_pos(pos).commit_id() == bad_id {
1590 Err(RevsetEvaluationError::Other("bad".into()))
1591 } else {
1592 Ok(true)
1593 }
1594 }),
1595 })
1596 };
1597
1598 let set = make_bad_set(&[&id_2, &id_1, &id_0], &id_1);
1600 assert_eq!(
1601 try_collect_vec(set.positions().attach(index).take(1)).unwrap(),
1602 make_positions(&[&id_2])
1603 );
1604 assert!(try_collect_vec(set.positions().attach(index).take(2)).is_err());
1605 let mut p = set.to_predicate_fn();
1606 assert!(p(index, get_pos(&id_2)).unwrap());
1607 assert!(p(index, get_pos(&id_1)).is_err());
1608
1609 let set = FilterRevset {
1611 candidates: make_bad_set(&[&id_2, &id_1, &id_0], &id_1),
1612 predicate: as_pure_predicate_fn(|_, _| Ok(true)),
1613 };
1614 assert_eq!(
1615 try_collect_vec(set.positions().attach(index).take(1)).unwrap(),
1616 make_positions(&[&id_2])
1617 );
1618 assert!(try_collect_vec(set.positions().attach(index).take(2)).is_err());
1619 let mut p = set.to_predicate_fn();
1620 assert!(p(index, get_pos(&id_2)).unwrap());
1621 assert!(p(index, get_pos(&id_1)).is_err());
1622
1623 let set = UnionRevset {
1625 set1: make_bad_set(&[&id_1], &id_1),
1626 set2: make_good_set(&[&id_2, &id_1]),
1627 };
1628 assert!(try_collect_vec(set.positions().attach(index).take(1)).is_err());
1629 let mut p = set.to_predicate_fn();
1630 assert!(p(index, get_pos(&id_2)).unwrap()); assert!(p(index, get_pos(&id_1)).is_err());
1632
1633 let set = UnionRevset {
1635 set1: make_good_set(&[&id_2, &id_1]),
1636 set2: make_bad_set(&[&id_1, &id_0], &id_0),
1637 };
1638 assert_eq!(
1639 try_collect_vec(set.positions().attach(index).take(2)).unwrap(),
1640 make_positions(&[&id_2, &id_1])
1641 );
1642 assert!(try_collect_vec(set.positions().attach(index).take(3)).is_err());
1643 let mut p = set.to_predicate_fn();
1644 assert!(p(index, get_pos(&id_2)).unwrap());
1645 assert!(p(index, get_pos(&id_1)).unwrap());
1646 assert!(p(index, get_pos(&id_0)).is_err());
1647
1648 let set = IntersectionRevset {
1650 set1: make_bad_set(&[&id_1], &id_1),
1651 set2: make_good_set(&[&id_2, &id_1]),
1652 };
1653 assert!(try_collect_vec(set.positions().attach(index).take(1)).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)).is_err());
1657
1658 let set = IntersectionRevset {
1660 set1: make_good_set(&[&id_2, &id_1, &id_0]),
1661 set2: make_bad_set(&[&id_1, &id_0], &id_0),
1662 };
1663 assert_eq!(
1664 try_collect_vec(set.positions().attach(index).take(1)).unwrap(),
1665 make_positions(&[&id_1])
1666 );
1667 assert!(try_collect_vec(set.positions().attach(index).take(2)).is_err());
1668 let mut p = set.to_predicate_fn();
1669 assert!(!p(index, get_pos(&id_2)).unwrap());
1670 assert!(p(index, get_pos(&id_1)).unwrap());
1671 assert!(p(index, get_pos(&id_0)).is_err());
1672
1673 let set = DifferenceRevset {
1675 set1: make_bad_set(&[&id_1], &id_1),
1676 set2: make_good_set(&[&id_2, &id_1]),
1677 };
1678 assert!(try_collect_vec(set.positions().attach(index).take(1)).is_err());
1679 let mut p = set.to_predicate_fn();
1680 assert!(!p(index, get_pos(&id_2)).unwrap());
1681 assert!(p(index, get_pos(&id_1)).is_err());
1682
1683 let set = DifferenceRevset {
1685 set1: make_good_set(&[&id_2, &id_1, &id_0]),
1686 set2: make_bad_set(&[&id_1, &id_0], &id_0),
1687 };
1688 assert_eq!(
1689 try_collect_vec(set.positions().attach(index).take(1)).unwrap(),
1690 make_positions(&[&id_2])
1691 );
1692 assert!(try_collect_vec(set.positions().attach(index).take(2)).is_err());
1693 let mut p = set.to_predicate_fn();
1694 assert!(p(index, get_pos(&id_2)).unwrap());
1695 assert!(!p(index, get_pos(&id_1)).unwrap());
1696 assert!(p(index, get_pos(&id_0)).is_err());
1697 }
1698
1699 #[test]
1700 fn test_positions_accumulator() {
1701 let mut new_change_id = change_id_generator();
1702 let mut index = DefaultMutableIndex::full(3, 16);
1703 let id_0 = CommitId::from_hex("000000");
1704 let id_1 = CommitId::from_hex("111111");
1705 let id_2 = CommitId::from_hex("222222");
1706 let id_3 = CommitId::from_hex("333333");
1707 let id_4 = CommitId::from_hex("444444");
1708 index.add_commit_data(id_0.clone(), new_change_id(), &[]);
1709 index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
1710 index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
1711 index.add_commit_data(id_3.clone(), new_change_id(), &[id_2.clone()]);
1712 index.add_commit_data(id_4.clone(), new_change_id(), &[id_3.clone()]);
1713
1714 let index = index.as_composite();
1715 let get_pos = |id: &CommitId| index.commit_id_to_pos(id).unwrap();
1716 let make_positions = |ids: &[&CommitId]| ids.iter().copied().map(get_pos).collect_vec();
1717 let make_set = |ids: &[&CommitId]| -> Box<dyn InternalRevset> {
1718 let positions = make_positions(ids);
1719 Box::new(EagerRevset { positions })
1720 };
1721
1722 let full_set = make_set(&[&id_4, &id_3, &id_2, &id_1, &id_0]);
1723
1724 let positions_accum = PositionsAccumulator::new(index, full_set.positions());
1726
1727 assert!(positions_accum.contains(&id_3).unwrap());
1728 assert_eq!(positions_accum.consumed_len(), 2);
1729
1730 assert!(positions_accum.contains(&id_0).unwrap());
1731 assert_eq!(positions_accum.consumed_len(), 5);
1732
1733 assert!(positions_accum.contains(&id_3).unwrap());
1734 assert_eq!(positions_accum.consumed_len(), 5);
1735
1736 let positions_accum = PositionsAccumulator::new(index, full_set.positions());
1738
1739 assert!(!positions_accum
1740 .contains(&CommitId::from_hex("999999"))
1741 .unwrap());
1742 assert_eq!(positions_accum.consumed_len(), 0);
1743
1744 let set = make_set(&[&id_3, &id_2, &id_1]);
1746 let positions_accum = PositionsAccumulator::new(index, set.positions());
1747
1748 assert!(!positions_accum.contains(&id_4).unwrap());
1749 assert_eq!(positions_accum.consumed_len(), 1);
1750
1751 assert!(positions_accum.contains(&id_3).unwrap());
1752 assert_eq!(positions_accum.consumed_len(), 1);
1753
1754 assert!(!positions_accum.contains(&id_0).unwrap());
1755 assert_eq!(positions_accum.consumed_len(), 3);
1756
1757 assert!(positions_accum.contains(&id_1).unwrap());
1758 }
1759
1760 fn diff_match_lines_samples() -> (Merge<BString>, Merge<BString>) {
1761 let base = indoc! {"
1771 line 1
1772 line 2
1773 line 3
1774 line 4
1775 "};
1776 let left1 = indoc! {"
1777 line 1
1778 line 2
1779 left 3.1
1780 left 3.2
1781 line 4
1782 line 5
1783 "};
1784 let left2 = indoc! {"
1785 left 1.1
1786 line 2
1787 left 3.1
1788 left 3.2
1789 left 3.3
1790 line 4
1791 line 5
1792 "};
1793 let right1 = indoc! {"
1794 line 1
1795 line 2
1796 right 3.1
1797 line 4
1798 line 5
1799 "};
1800 let right2 = indoc! {"
1801 line 1
1802 line 2
1803 right 3.1
1804 line 4
1805 "};
1806
1807 let conflict1 = Merge::from_vec([left1, base, right1].map(BString::from).to_vec());
1808 let conflict2 = Merge::from_vec([left2, base, right2].map(BString::from).to_vec());
1809 (conflict1, conflict2)
1810 }
1811
1812 #[test]
1813 fn test_diff_match_lines_between_resolved() {
1814 let (conflict1, conflict2) = diff_match_lines_samples();
1815 let left1 = Merge::resolved(conflict1.first().clone());
1816 let left2 = Merge::resolved(conflict2.first().clone());
1817 let diff = |needle: &str| {
1818 let pattern = StringPattern::substring(needle);
1819 diff_match_lines(&left1, &left2, &pattern).unwrap()
1820 };
1821
1822 assert!(diff(""));
1823 assert!(!diff("no match"));
1824 assert!(diff("line "));
1825 assert!(diff(" 1"));
1826 assert!(!diff(" 2"));
1827 assert!(diff(" 3"));
1828 assert!(!diff(" 3.1"));
1829 assert!(!diff(" 3.2"));
1830 assert!(diff(" 3.3"));
1831 assert!(!diff(" 4"));
1832 assert!(!diff(" 5"));
1833 }
1834
1835 #[test]
1836 fn test_diff_match_lines_between_conflicts() {
1837 let (conflict1, conflict2) = diff_match_lines_samples();
1838 let diff = |needle: &str| {
1839 let pattern = StringPattern::substring(needle);
1840 diff_match_lines(&conflict1, &conflict2, &pattern).unwrap()
1841 };
1842
1843 assert!(diff(""));
1844 assert!(!diff("no match"));
1845 assert!(diff("line "));
1846 assert!(diff(" 1"));
1847 assert!(!diff(" 2"));
1848 assert!(diff(" 3"));
1849 assert!(!diff(" 3.1"));
1853 assert!(!diff(" 3.2"));
1854 assert!(diff(" 3.3"));
1855 assert!(!diff(" 4"));
1856 assert!(!diff(" 5")); }
1858
1859 #[test]
1860 fn test_diff_match_lines_between_resolved_and_conflict() {
1861 let (_conflict1, conflict2) = diff_match_lines_samples();
1862 let base = Merge::resolved(conflict2.get_remove(0).unwrap().clone());
1863 let diff = |needle: &str| {
1864 let pattern = StringPattern::substring(needle);
1865 diff_match_lines(&base, &conflict2, &pattern).unwrap()
1866 };
1867
1868 assert!(diff(""));
1869 assert!(!diff("no match"));
1870 assert!(diff("line "));
1871 assert!(diff(" 1"));
1872 assert!(!diff(" 2"));
1873 assert!(diff(" 3"));
1874 assert!(diff(" 3.1"));
1875 assert!(diff(" 3.2"));
1876 assert!(!diff(" 4"));
1877 assert!(diff(" 5"));
1878 }
1879}