jj_lib/default_index/
revset_engine.rs

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