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