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 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    /// Creates function that tests if the given entry is included in the set.
77    ///
78    /// The predicate function is evaluated in order of `RevsetIterator`.
79    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    // All revsets currently iterate in order of descending index position
95    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            // Exercise the estimation feature in tests. (If we ever have a Revset
197            // implementation in production code that returns estimates, we can probably
198            // remove this and rewrite the associated tests.)
199            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
223/// Incrementally consumes `RevWalk` of the revset collecting positions.
224struct 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    /// Checks whether the commit is in the revset.
239    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
260/// Helper struct for [`PositionsAccumulator`] to simplify interior mutability.
261struct PositionsAccumulatorInner<'a> {
262    walk: BoxedRevWalk<'a>,
263    consumed_positions: Vec<IndexPosition>,
264}
265
266impl PositionsAccumulatorInner<'_> {
267    /// Consumes `RevWalk` to a desired position but not deeper.
268    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/// Adapter for precomputed `IndexPosition`s.
288#[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
328/// Adapter for infallible `RevWalk` of `IndexPosition`s.
329struct 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
486/// `RevWalk` node that merges two sorted walk nodes.
487///
488/// The input items should be sorted in ascending order by the `cmp` function.
489struct 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
581/// `RevWalk` node that intersects two sorted walk nodes.
582///
583/// The input items should be sorted in ascending order by the `cmp` function.
584struct 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    // The minuend (what to subtract from)
652    set1: S1,
653    // The subtrahend (what to subtract)
654    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
696/// `RevWalk` node that subtracts `walk2` items from `walk1`.
697///
698/// The input items should be sorted in ascending order by the `cmp` function.
699struct 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                // Pre-filter heads so queries like 'immutable_heads()..' can
826                // terminate early. immutable_heads() usually includes some
827                // visible heads, which can be trivially rejected.
828                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                    // TODO: Suppose heads include all visible heads, ToPredicateFn version can be
874                    // optimized to only test the predicate()
875                    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                    // For small generation range, it might be better to build a reachable map
887                    // with generation bit set, which can be calculated incrementally from roots:
888                    //   reachable[pos] = (reachable[parent_pos] | ...) << 1
889                    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                // Compute all reachable subgraphs.
904                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                // Identify disjoint sets reachable from sources.
916                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                // Invalid commit IDs should be rejected by the revset frontend,
1041                // but there are a few edge cases that break the precondition.
1042                // For example, in jj <= 0.22, the root commit doesn't exist in
1043                // the root operation.
1044                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, // tie-breaker
1073        }
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        // Maintain min-heap containing the latest (greatest) count items. For small
1085        // count and large candidate set, this is probably cheaper than building vec
1086        // and applying selection algorithm.
1087        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        // Fast path: no need to load the root tree
1270        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    // Conflict resolution is expensive, try that only for matched files.
1279    let from_tree = rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?;
1280    let to_tree = commit.tree()?;
1281    // TODO: handle copy tracking
1282    let mut tree_diff = from_tree.diff_stream(&to_tree, matcher);
1283    async {
1284        // TODO: Resolve values concurrently
1285        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    // Conflict resolution is expensive, try that only for matched files.
1307    let from_tree = rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?;
1308    let to_tree = commit.tree()?;
1309    // TODO: handle copy tracking
1310    let mut tree_diff = from_tree.diff_stream(&to_tree, files_matcher);
1311    async {
1312        // TODO: Resolve values concurrently
1313        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            // Conflicts are compared in materialized form. Alternatively,
1320            // conflict pairs can be compared one by one. #4062
1321            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            // Filter lines prior to comparison. This might produce inferior
1327            // hunks due to lack of contexts, but is way faster than full diff.
1328            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    // The pattern is matched line by line so that it can be anchored to line
1344    // start/end. For example, exact:"" will match blank lines.
1345    text.split_inclusive(|b| *b == b'\n').filter(|line| {
1346        let line = line.strip_suffix(b"\n").unwrap_or(line);
1347        // TODO: add .matches_bytes() or .to_bytes_matcher()
1348        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    /// Generator of unique 16-byte ChangeId excluding root id
1385    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        // Uninteresting entries can be skipped
1425        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        // Intersection by FilterRevset
1448        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        // Error from filter predicate
1543        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        // Error from filter candidates
1554        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        // Error from left side of union, immediately
1568        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()); // works because bad id isn't visited
1575        assert!(p(index, get_pos(&id_1)).is_err());
1576
1577        // Error from right side of union, lazily
1578        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        // Error from left side of intersection, immediately
1593        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        // Error from right side of intersection, lazily
1603        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        // Error from left side of difference, immediately
1618        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        // Error from right side of difference, lazily
1628        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        // Consumes entries incrementally
1669        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        // Does not consume positions for unknown commits
1681        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        // Does not consume without necessity
1689        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}