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