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