jj_lib/
merge.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//! Generic algorithms for working with merged values, plus specializations for
16//! some common types of merged values.
17
18use std::borrow::Borrow;
19use std::collections::HashMap;
20use std::fmt::Debug;
21use std::fmt::Formatter;
22use std::fmt::Write as _;
23use std::future::Future;
24use std::hash::Hash;
25use std::iter::zip;
26use std::slice;
27use std::sync::Arc;
28
29use futures::future::try_join_all;
30use itertools::Itertools as _;
31use smallvec::SmallVec;
32use smallvec::smallvec_inline;
33
34use crate::backend;
35use crate::backend::BackendResult;
36use crate::backend::CopyId;
37use crate::backend::FileId;
38use crate::backend::TreeValue;
39use crate::content_hash::ContentHash;
40use crate::content_hash::DigestUpdate;
41use crate::repo_path::RepoPath;
42use crate::store::Store;
43use crate::tree::Tree;
44
45/// Attempt to resolve trivial conflicts between the inputs. There must be
46/// an odd number of terms.
47pub fn trivial_merge<T>(values: &[T]) -> Option<&T>
48where
49    T: Eq + Hash,
50{
51    assert!(
52        values.len() % 2 == 1,
53        "trivial_merge() requires an odd number of terms"
54    );
55    // Optimize the common cases of 3-way merge and 1-way (non-)merge
56    if let [add] = values {
57        return Some(add);
58    } else if let [add0, remove, add1] = values {
59        return if add0 == add1 {
60            Some(add0)
61        } else if add0 == remove {
62            Some(add1)
63        } else if add1 == remove {
64            Some(add0)
65        } else {
66            None
67        };
68    }
69
70    // Number of occurrences of each value, with positive indexes counted as +1 and
71    // negative as -1, thereby letting positive and negative terms with the same
72    // value (i.e. key in the map) cancel each other.
73    let mut counts: HashMap<&T, i32> = HashMap::new();
74    for (value, n) in zip(values, [1, -1].into_iter().cycle()) {
75        counts.entry(value).and_modify(|e| *e += n).or_insert(n);
76    }
77
78    // Collect non-zero value. Values with a count of 0 means that they have
79    // cancelled out.
80    counts.retain(|_, count| *count != 0);
81    if counts.len() == 1 {
82        // If there is a single value with a count of 1 left, then that is the result.
83        let (value, count) = counts.into_iter().next().unwrap();
84        assert_eq!(count, 1);
85        Some(value)
86    } else if counts.len() == 2 {
87        // All sides made the same change.
88        // This matches what Git and Mercurial do (in the 3-way case at least), but not
89        // what Darcs does. It means that repeated 3-way merging of multiple trees may
90        // give different results depending on the order of merging.
91        // TODO: Consider removing this special case, making the algorithm more strict,
92        // and maybe add a more lenient version that is used when the user explicitly
93        // asks for conflict resolution.
94        let [(value1, count1), (value2, count2)] = counts.into_iter().next_array().unwrap();
95        assert_eq!(count1 + count2, 1);
96        if count1 > 0 {
97            Some(value1)
98        } else {
99            Some(value2)
100        }
101    } else {
102        None
103    }
104}
105
106/// A generic representation of merged values.
107///
108/// There is exactly one more `adds()` than `removes()`. When interpreted as a
109/// series of diffs, the merge's (i+1)-st add is matched with the i-th
110/// remove. The zeroth add is considered a diff from the non-existent state.
111#[derive(PartialEq, Eq, Hash, Clone, serde::Serialize)]
112#[serde(transparent)]
113pub struct Merge<T> {
114    /// Alternates between positive and negative terms, starting with positive.
115    values: SmallVec<[T; 1]>,
116}
117
118impl<T: Debug> Debug for Merge<T> {
119    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
120        // Format like an enum with two variants to make it less verbose in the common
121        // case of a resolved state.
122        if let Some(value) = self.as_resolved() {
123            f.debug_tuple("Resolved").field(value).finish()
124        } else {
125            f.debug_tuple("Conflicted").field(&self.values).finish()
126        }
127    }
128}
129
130impl<T> Merge<T> {
131    /// Creates a `Merge` from the given values, in which positive and negative
132    /// terms alternate.
133    pub fn from_vec(values: impl Into<SmallVec<[T; 1]>>) -> Self {
134        let values = values.into();
135        assert!(values.len() % 2 != 0, "must have an odd number of terms");
136        Self { values }
137    }
138
139    /// Creates a new merge object from the given removes and adds.
140    pub fn from_removes_adds(
141        removes: impl IntoIterator<Item = T>,
142        adds: impl IntoIterator<Item = T>,
143    ) -> Self {
144        let removes = removes.into_iter();
145        let mut adds = adds.into_iter();
146        let mut values = SmallVec::with_capacity(removes.size_hint().0 * 2 + 1);
147        values.push(adds.next().expect("must have at least one add"));
148        for diff in removes.zip_longest(adds) {
149            let (remove, add) = diff.both().expect("must have one more adds than removes");
150            values.extend([remove, add]);
151        }
152        Self { values }
153    }
154
155    /// Creates a `Merge` with a single resolved value.
156    pub const fn resolved(value: T) -> Self {
157        Self {
158            values: smallvec_inline![value],
159        }
160    }
161
162    /// Create a `Merge` from a `removes` and `adds`, padding with `None` to
163    /// make sure that there is exactly one more `adds` than `removes`.
164    pub fn from_legacy_form(
165        removes: impl IntoIterator<Item = T>,
166        adds: impl IntoIterator<Item = T>,
167    ) -> Merge<Option<T>> {
168        let removes = removes.into_iter();
169        let mut adds = adds.into_iter().fuse();
170        let mut values = smallvec_inline![adds.next()];
171        for diff in removes.zip_longest(adds) {
172            let (remove, add) = diff.map_any(Some, Some).or_default();
173            values.extend([remove, add]);
174        }
175        Merge { values }
176    }
177
178    /// The removed values, also called negative terms.
179    pub fn removes(&self) -> impl ExactSizeIterator<Item = &T> {
180        self.values[1..].iter().step_by(2)
181    }
182
183    /// The added values, also called positive terms.
184    pub fn adds(&self) -> impl ExactSizeIterator<Item = &T> {
185        self.values.iter().step_by(2)
186    }
187
188    /// Returns the zeroth added value, which is guaranteed to exist.
189    pub fn first(&self) -> &T {
190        &self.values[0]
191    }
192
193    /// Returns the `index`-th removed value, which is considered belonging to
194    /// the `index`-th diff pair.
195    pub fn get_remove(&self, index: usize) -> Option<&T> {
196        self.values.get(index * 2 + 1)
197    }
198
199    /// Returns the `index`-th added value, which is considered belonging to the
200    /// `index-1`-th diff pair. The zeroth add is a diff from the non-existent
201    /// state.
202    pub fn get_add(&self, index: usize) -> Option<&T> {
203        self.values.get(index * 2)
204    }
205
206    /// Removes the specified "removed"/"added" values. The removed slots are
207    /// replaced by the last "removed"/"added" values.
208    pub fn swap_remove(&mut self, remove_index: usize, add_index: usize) -> (T, T) {
209        // Swap with the last "added" and "removed" values in order.
210        let add = self.values.swap_remove(add_index * 2);
211        let remove = self.values.swap_remove(remove_index * 2 + 1);
212        (remove, add)
213    }
214
215    /// The number of positive terms in the conflict.
216    pub fn num_sides(&self) -> usize {
217        self.values.len() / 2 + 1
218    }
219
220    /// Whether this merge is resolved. Does not resolve trivial merges.
221    pub fn is_resolved(&self) -> bool {
222        self.values.len() == 1
223    }
224
225    /// Returns the resolved value, if this merge is resolved. Does not
226    /// resolve trivial merges.
227    pub fn as_resolved(&self) -> Option<&T> {
228        if let [value] = &self.values[..] {
229            Some(value)
230        } else {
231            None
232        }
233    }
234
235    /// Returns the resolved value, if this merge is resolved. Otherwise returns
236    /// the merge itself as an `Err`. Does not resolve trivial merges.
237    pub fn into_resolved(mut self) -> Result<T, Self> {
238        if self.values.len() == 1 {
239            Ok(self.values.pop().unwrap())
240        } else {
241            Err(self)
242        }
243    }
244
245    /// Returns a vector mapping of a value's index in the simplified merge to
246    /// its original index in the unsimplified merge.
247    ///
248    /// The merge is simplified by removing identical values in add and remove
249    /// values.
250    fn get_simplified_mapping(&self) -> Vec<usize>
251    where
252        T: PartialEq,
253    {
254        let unsimplified_len = self.values.len();
255        let mut simplified_to_original_indices = (0..unsimplified_len).collect_vec();
256
257        let mut add_index = 0;
258        while add_index < simplified_to_original_indices.len() {
259            let add = &self.values[simplified_to_original_indices[add_index]];
260            let mut remove_indices = simplified_to_original_indices
261                .iter()
262                .enumerate()
263                .skip(1)
264                .step_by(2);
265            if let Some((remove_index, _)) = remove_indices
266                .find(|&(_, original_remove_index)| &self.values[*original_remove_index] == add)
267            {
268                // Align the current "add" value to the `remove_index/2`-th diff, then
269                // delete the diff pair.
270                simplified_to_original_indices.swap(remove_index + 1, add_index);
271                simplified_to_original_indices.drain(remove_index..remove_index + 2);
272            } else {
273                add_index += 2;
274            }
275        }
276
277        simplified_to_original_indices
278    }
279
280    /// Simplify the merge by joining diffs like A->B and B->C into A->C.
281    /// Also drops trivial diffs like A->A.
282    #[must_use]
283    pub fn simplify(&self) -> Self
284    where
285        T: PartialEq + Clone,
286    {
287        let mapping = self.get_simplified_mapping();
288        // Reorder values based on their new indices in the simplified merge.
289        let values = mapping
290            .iter()
291            .map(|index| self.values[*index].clone())
292            .collect();
293        Self { values }
294    }
295
296    /// Updates the merge based on the given simplified merge.
297    pub fn update_from_simplified(mut self, simplified: Self) -> Self
298    where
299        T: PartialEq,
300    {
301        let mapping = self.get_simplified_mapping();
302        assert_eq!(mapping.len(), simplified.values.len());
303        for (index, value) in mapping.into_iter().zip(simplified.values.into_iter()) {
304            self.values[index] = value;
305        }
306        self
307    }
308
309    /// If this merge can be trivially resolved, returns the value it resolves
310    /// to.
311    pub fn resolve_trivial(&self) -> Option<&T>
312    where
313        T: Eq + Hash,
314    {
315        trivial_merge(&self.values)
316    }
317
318    /// Pads this merge with to the specified number of sides with the specified
319    /// value. No-op if the requested size is not larger than the current size.
320    pub fn pad_to(&mut self, num_sides: usize, value: &T)
321    where
322        T: Clone,
323    {
324        if num_sides <= self.num_sides() {
325            return;
326        }
327        self.values.resize(num_sides * 2 - 1, value.clone());
328    }
329
330    /// Returns a slice containing the terms. The items will alternate between
331    /// positive and negative terms, starting with positive (since there's one
332    /// more of those).
333    pub fn as_slice(&self) -> &[T] {
334        &self.values
335    }
336
337    /// Returns an iterator over references to the terms. The items will
338    /// alternate between positive and negative terms, starting with
339    /// positive (since there's one more of those).
340    pub fn iter(&self) -> slice::Iter<'_, T> {
341        self.values.iter()
342    }
343
344    /// A version of `Merge::iter()` that iterates over mutable references.
345    pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
346        self.values.iter_mut()
347    }
348
349    /// Creates a new merge by applying `f` to each remove and add.
350    pub fn map<'a, U>(&'a self, f: impl FnMut(&'a T) -> U) -> Merge<U> {
351        let values = self.values.iter().map(f).collect();
352        Merge { values }
353    }
354
355    /// Creates a new merge by applying `f` to each remove and add, returning
356    /// `Err if `f` returns `Err` for any of them.
357    pub fn try_map<'a, U, E>(
358        &'a self,
359        f: impl FnMut(&'a T) -> Result<U, E>,
360    ) -> Result<Merge<U>, E> {
361        let values = self.values.iter().map(f).try_collect()?;
362        Ok(Merge { values })
363    }
364
365    /// Creates a new merge by applying the async function `f` to each remove
366    /// and add, running them concurrently, and returning `Err if `f`
367    /// returns `Err` for any of them.
368    pub async fn try_map_async<'a, F, U, E>(
369        &'a self,
370        f: impl FnMut(&'a T) -> F,
371    ) -> Result<Merge<U>, E>
372    where
373        F: Future<Output = Result<U, E>>,
374    {
375        let values = try_join_all(self.values.iter().map(f)).await?;
376        Ok(Merge {
377            values: values.into(),
378        })
379    }
380}
381
382/// Helper for consuming items from an iterator and then creating a `Merge`.
383///
384/// By not collecting directly into `Merge`, we can avoid creating invalid
385/// instances of it. If we had `Merge::from_iter()` we would need to allow it to
386/// accept iterators of any length (including 0). We couldn't make it panic on
387/// even lengths because we can get passed such iterators from e.g.
388/// `Option::from_iter()`. By collecting into `MergeBuilder` instead, we move
389/// the checking until after `from_iter()` (to `MergeBuilder::build()`).
390#[derive(Clone, Debug, PartialEq, Eq)]
391pub struct MergeBuilder<T> {
392    values: SmallVec<[T; 1]>,
393}
394
395impl<T> Default for MergeBuilder<T> {
396    fn default() -> Self {
397        Self {
398            values: Default::default(),
399        }
400    }
401}
402
403impl<T> MergeBuilder<T> {
404    /// Requires that exactly one more "adds" than "removes" have been added to
405    /// this builder.
406    pub fn build(self) -> Merge<T> {
407        Merge::from_vec(self.values)
408    }
409}
410
411impl<T> IntoIterator for Merge<T> {
412    type Item = T;
413    type IntoIter = smallvec::IntoIter<[T; 1]>;
414
415    fn into_iter(self) -> Self::IntoIter {
416        self.values.into_iter()
417    }
418}
419
420impl<T> FromIterator<T> for MergeBuilder<T> {
421    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
422        let mut builder = Self::default();
423        builder.extend(iter);
424        builder
425    }
426}
427
428impl<T> Extend<T> for MergeBuilder<T> {
429    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
430        self.values.extend(iter);
431    }
432}
433
434impl<T> Merge<Option<T>> {
435    /// Creates a resolved merge with a value of `None`.
436    pub fn absent() -> Self {
437        Self::resolved(None)
438    }
439
440    /// Creates a resolved merge with a value of `Some(value)`.
441    pub fn normal(value: T) -> Self {
442        Self::resolved(Some(value))
443    }
444
445    /// Whether this represents a resolved value of `None`.
446    pub fn is_absent(&self) -> bool {
447        matches!(self.as_resolved(), Some(None))
448    }
449
450    /// The opposite of `is_absent()`.
451    pub fn is_present(&self) -> bool {
452        !self.is_absent()
453    }
454
455    /// Returns the value if this is present and non-conflicting.
456    pub fn as_normal(&self) -> Option<&T> {
457        self.as_resolved()?.as_ref()
458    }
459
460    /// Creates lists of `removes` and `adds` from a `Merge` by dropping
461    /// `None` values. Note that the conversion is lossy: the order of `None`
462    /// values is not preserved when converting back to a `Merge`.
463    pub fn into_legacy_form(self) -> (Vec<T>, Vec<T>) {
464        // Allocate the maximum size assuming there would be few `None`s.
465        let mut removes = Vec::with_capacity(self.values.len() / 2);
466        let mut adds = Vec::with_capacity(self.values.len() / 2 + 1);
467        let mut values = self.values.into_iter();
468        adds.extend(values.next().unwrap());
469        while let Some(remove) = values.next() {
470            removes.extend(remove);
471            adds.extend(values.next().unwrap());
472        }
473        (removes, adds)
474    }
475}
476
477impl<T: Clone> Merge<Option<&T>> {
478    /// Creates a new merge by cloning inner `Option<&T>`s.
479    pub fn cloned(&self) -> Merge<Option<T>> {
480        self.map(|value| value.cloned())
481    }
482}
483
484impl<T> Merge<Merge<T>> {
485    /// Flattens a nested merge into a regular merge.
486    ///
487    /// Let's say we have a 3-way merge of 3-way merges like this:
488    ///
489    /// ```text
490    /// 4 5   7 8
491    ///  3     6
492    ///    1 2
493    ///     0
494    /// ```
495    ///
496    /// Flattening that results in this 9-way merge:
497    ///
498    /// ```text
499    /// 4 5 0 7 8
500    ///  3 2 1 6
501    /// ```
502    pub fn flatten(self) -> Merge<T> {
503        let mut outer_values = self.values.into_iter();
504        let mut result = outer_values.next().unwrap();
505        while let Some(mut remove) = outer_values.next() {
506            // Add removes reversed, and with the first element moved last, so we preserve
507            // the diffs
508            remove.values.rotate_left(1);
509            for i in 0..remove.values.len() / 2 {
510                remove.values.swap(i * 2, i * 2 + 1);
511            }
512            result.values.extend(remove.values);
513            let add = outer_values.next().unwrap();
514            result.values.extend(add.values);
515        }
516        result
517    }
518}
519
520impl<T: ContentHash> ContentHash for Merge<T> {
521    fn hash(&self, state: &mut impl DigestUpdate) {
522        self.values.hash(state);
523    }
524}
525
526/// Borrowed `MergedTreeValue`.
527pub type MergedTreeVal<'a> = Merge<Option<&'a TreeValue>>;
528
529/// The value at a given path in a commit.
530///
531/// It depends on the context whether it can be absent
532/// (`Merge::is_absent()`). For example, when getting the value at a
533/// specific path, it may be, but when iterating over entries in a
534/// tree, it shouldn't be.
535pub type MergedTreeValue = Merge<Option<TreeValue>>;
536
537impl MergedTreeValue {
538    /// Create a `Merge` from a `backend::Conflict`, padding with `None` to
539    /// make sure that there is exactly one more `adds()` than `removes()`.
540    pub fn from_backend_conflict(conflict: backend::Conflict) -> Self {
541        let removes = conflict.removes.into_iter().map(|term| term.value);
542        let adds = conflict.adds.into_iter().map(|term| term.value);
543        Merge::from_legacy_form(removes, adds)
544    }
545
546    /// Creates a `backend::Conflict` from a `Merge` by dropping `None`
547    /// values. Note that the conversion is lossy: the order of `None` values is
548    /// not preserved when converting back to a `Merge`.
549    pub fn into_backend_conflict(self) -> backend::Conflict {
550        let (removes, adds) = self.into_legacy_form();
551        let removes = removes
552            .into_iter()
553            .map(|value| backend::ConflictTerm { value })
554            .collect();
555        let adds = adds
556            .into_iter()
557            .map(|value| backend::ConflictTerm { value })
558            .collect();
559        backend::Conflict { removes, adds }
560    }
561}
562
563impl<T> Merge<Option<T>>
564where
565    T: Borrow<TreeValue>,
566{
567    /// Whether this merge should be recursed into when doing directory walks.
568    pub fn is_tree(&self) -> bool {
569        self.is_present()
570            && self.iter().all(|value| {
571                matches!(
572                    borrow_tree_value(value.as_ref()),
573                    Some(TreeValue::Tree(_)) | None
574                )
575            })
576    }
577
578    /// Whether this merge is present and not a tree
579    pub fn is_file_like(&self) -> bool {
580        self.is_present() && !self.is_tree()
581    }
582
583    /// If this merge contains only files or absent entries, returns a merge of
584    /// the `FileId`s. The executable bits and copy IDs will be ignored. Use
585    /// `Merge::with_new_file_ids()` to produce a new merge with the original
586    /// executable bits preserved.
587    pub fn to_file_merge(&self) -> Option<Merge<Option<FileId>>> {
588        let file_ids = self
589            .try_map(|term| match borrow_tree_value(term.as_ref()) {
590                None => Ok(None),
591                Some(TreeValue::File {
592                    id,
593                    executable: _,
594                    copy_id: _,
595                }) => Ok(Some(id.clone())),
596                _ => Err(()),
597            })
598            .ok()?;
599
600        Some(file_ids)
601    }
602
603    /// If this merge contains only files or absent entries, returns a merge of
604    /// the files' executable bits.
605    pub fn to_executable_merge(&self) -> Option<Merge<Option<bool>>> {
606        self.try_map(|term| match borrow_tree_value(term.as_ref()) {
607            None => Ok(None),
608            Some(TreeValue::File {
609                id: _,
610                executable,
611                copy_id: _,
612            }) => Ok(Some(*executable)),
613            _ => Err(()),
614        })
615        .ok()
616    }
617
618    /// If this merge contains only files or absent entries, returns a merge of
619    /// the files' copy IDs.
620    pub fn to_copy_id_merge(&self) -> Option<Merge<Option<CopyId>>> {
621        self.try_map(|term| match borrow_tree_value(term.as_ref()) {
622            None => Ok(None),
623            Some(TreeValue::File {
624                id: _,
625                executable: _,
626                copy_id,
627            }) => Ok(Some(copy_id.clone())),
628            _ => Err(()),
629        })
630        .ok()
631    }
632
633    /// If every non-`None` term of a `MergedTreeValue`
634    /// is a `TreeValue::Tree`, this converts it to
635    /// a `Merge<Tree>`, with empty trees instead of
636    /// any `None` terms. Otherwise, returns `None`.
637    pub async fn to_tree_merge(
638        &self,
639        store: &Arc<Store>,
640        dir: &RepoPath,
641    ) -> BackendResult<Option<Merge<Tree>>> {
642        let tree_id_merge = self.try_map(|term| match borrow_tree_value(term.as_ref()) {
643            None => Ok(None),
644            Some(TreeValue::Tree(id)) => Ok(Some(id)),
645            Some(_) => Err(()),
646        });
647        if let Ok(tree_id_merge) = tree_id_merge {
648            Ok(Some(
649                tree_id_merge
650                    .try_map_async(async |id| {
651                        if let Some(id) = id {
652                            store.get_tree_async(dir.to_owned(), id).await
653                        } else {
654                            Ok(Tree::empty(store.clone(), dir.to_owned()))
655                        }
656                    })
657                    .await?,
658            ))
659        } else {
660            Ok(None)
661        }
662    }
663
664    /// Creates a new merge with the file ids from the given merge. In other
665    /// words, only the executable bits from `self` will be preserved.
666    ///
667    /// The given `file_ids` should have the same shape as `self`. Only the
668    /// `FileId` values may differ.
669    pub fn with_new_file_ids(&self, file_ids: &Merge<Option<FileId>>) -> Merge<Option<TreeValue>> {
670        assert_eq!(self.values.len(), file_ids.values.len());
671        let values = zip(self.iter(), file_ids.iter().cloned())
672            .map(
673                |(tree_value, file_id)| match (borrow_tree_value(tree_value.as_ref()), file_id) {
674                    (
675                        Some(TreeValue::File {
676                            id: _,
677                            executable,
678                            copy_id,
679                        }),
680                        Some(id),
681                    ) => Some(TreeValue::File {
682                        id,
683                        executable: *executable,
684                        copy_id: copy_id.clone(),
685                    }),
686                    (None, None) => None,
687                    (old, new) => panic!("incompatible update: {old:?} to {new:?}"),
688                },
689            )
690            .collect();
691        Merge { values }
692    }
693
694    /// Give a summary description of the conflict's "removes" and "adds"
695    pub fn describe(&self) -> String {
696        let mut buf = String::new();
697        writeln!(buf, "Conflict:").unwrap();
698        for term in self.removes().flatten() {
699            writeln!(buf, "  Removing {}", describe_conflict_term(term.borrow())).unwrap();
700        }
701        for term in self.adds().flatten() {
702            writeln!(buf, "  Adding {}", describe_conflict_term(term.borrow())).unwrap();
703        }
704        buf
705    }
706}
707
708fn borrow_tree_value<T: Borrow<TreeValue> + ?Sized>(term: Option<&T>) -> Option<&TreeValue> {
709    term.map(|value| value.borrow())
710}
711
712fn describe_conflict_term(value: &TreeValue) -> String {
713    match value {
714        TreeValue::File {
715            id,
716            executable: false,
717            copy_id: _,
718        } => {
719            // TODO: include the copy here once we start using it
720            format!("file with id {id}")
721        }
722        TreeValue::File {
723            id,
724            executable: true,
725            copy_id: _,
726        } => {
727            // TODO: include the copy here once we start using it
728            format!("executable file with id {id}")
729        }
730        TreeValue::Symlink(id) => {
731            format!("symlink with id {id}")
732        }
733        TreeValue::Tree(id) => {
734            format!("tree with id {id}")
735        }
736        TreeValue::GitSubmodule(id) => {
737            format!("Git submodule with id {id}")
738        }
739        TreeValue::Conflict(id) => {
740            format!("Conflict with id {id}")
741        }
742    }
743}
744
745#[cfg(test)]
746mod tests {
747    use super::*;
748
749    fn c<T: Clone>(terms: &[T]) -> Merge<T> {
750        Merge::from_vec(terms.to_vec())
751    }
752
753    #[test]
754    fn test_trivial_merge() {
755        assert_eq!(trivial_merge(&[0]), Some(&0));
756        assert_eq!(trivial_merge(&[0, 0, 0]), Some(&0));
757        assert_eq!(trivial_merge(&[0, 0, 1]), Some(&1));
758        assert_eq!(trivial_merge(&[0, 1, 0]), Some(&0));
759        assert_eq!(trivial_merge(&[0, 1, 1]), Some(&0));
760        assert_eq!(trivial_merge(&[0, 1, 2]), None);
761        assert_eq!(trivial_merge(&[0, 0, 0, 0, 0]), Some(&0));
762        assert_eq!(trivial_merge(&[0, 0, 0, 0, 1]), Some(&1));
763        assert_eq!(trivial_merge(&[0, 0, 0, 1, 0]), Some(&0));
764        assert_eq!(trivial_merge(&[0, 0, 0, 1, 1]), Some(&0));
765        assert_eq!(trivial_merge(&[0, 0, 0, 1, 2]), None);
766        assert_eq!(trivial_merge(&[0, 0, 1, 0, 0]), Some(&1));
767        assert_eq!(trivial_merge(&[0, 0, 1, 0, 1]), Some(&1));
768        assert_eq!(trivial_merge(&[0, 0, 1, 0, 2]), None);
769        assert_eq!(trivial_merge(&[0, 0, 1, 1, 0]), Some(&0));
770        assert_eq!(trivial_merge(&[0, 0, 1, 1, 1]), Some(&1));
771        assert_eq!(trivial_merge(&[0, 0, 1, 1, 2]), Some(&2));
772        assert_eq!(trivial_merge(&[0, 0, 1, 2, 0]), None);
773        assert_eq!(trivial_merge(&[0, 0, 1, 2, 1]), Some(&1));
774        assert_eq!(trivial_merge(&[0, 0, 1, 2, 2]), Some(&1));
775        assert_eq!(trivial_merge(&[0, 0, 1, 2, 3]), None);
776        assert_eq!(trivial_merge(&[0, 1, 0, 0, 0]), Some(&0));
777        assert_eq!(trivial_merge(&[0, 1, 0, 0, 1]), Some(&0));
778        assert_eq!(trivial_merge(&[0, 1, 0, 0, 2]), None);
779        assert_eq!(trivial_merge(&[0, 1, 0, 1, 0]), Some(&0));
780        assert_eq!(trivial_merge(&[0, 1, 0, 1, 1]), Some(&0));
781        assert_eq!(trivial_merge(&[0, 1, 0, 1, 2]), None);
782        assert_eq!(trivial_merge(&[0, 1, 0, 2, 0]), None);
783        assert_eq!(trivial_merge(&[0, 1, 0, 2, 1]), Some(&0));
784        assert_eq!(trivial_merge(&[0, 1, 0, 2, 2]), Some(&0));
785        assert_eq!(trivial_merge(&[0, 1, 0, 2, 3]), None);
786        assert_eq!(trivial_merge(&[0, 1, 1, 0, 0]), Some(&0));
787        assert_eq!(trivial_merge(&[0, 1, 1, 0, 1]), Some(&1));
788        assert_eq!(trivial_merge(&[0, 1, 1, 0, 2]), Some(&2));
789        assert_eq!(trivial_merge(&[0, 1, 1, 1, 0]), Some(&0));
790        assert_eq!(trivial_merge(&[0, 1, 1, 1, 1]), Some(&0));
791        assert_eq!(trivial_merge(&[0, 1, 1, 1, 2]), None);
792        assert_eq!(trivial_merge(&[0, 1, 1, 2, 0]), Some(&0));
793        assert_eq!(trivial_merge(&[0, 1, 1, 2, 1]), None);
794        assert_eq!(trivial_merge(&[0, 1, 1, 2, 2]), Some(&0));
795        assert_eq!(trivial_merge(&[0, 1, 1, 2, 3]), None);
796        assert_eq!(trivial_merge(&[0, 1, 2, 0, 0]), None);
797        assert_eq!(trivial_merge(&[0, 1, 2, 0, 1]), Some(&2));
798        assert_eq!(trivial_merge(&[0, 1, 2, 0, 2]), Some(&2));
799        assert_eq!(trivial_merge(&[0, 1, 2, 0, 3]), None);
800        assert_eq!(trivial_merge(&[0, 1, 2, 1, 0]), None);
801        assert_eq!(trivial_merge(&[0, 1, 2, 1, 1]), None);
802        assert_eq!(trivial_merge(&[0, 1, 2, 1, 2]), None);
803        assert_eq!(trivial_merge(&[0, 1, 2, 1, 3]), None);
804        assert_eq!(trivial_merge(&[0, 1, 2, 2, 0]), Some(&0));
805        assert_eq!(trivial_merge(&[0, 1, 2, 2, 1]), Some(&0));
806        assert_eq!(trivial_merge(&[0, 1, 2, 2, 2]), None);
807        assert_eq!(trivial_merge(&[0, 1, 2, 2, 3]), None);
808        assert_eq!(trivial_merge(&[0, 1, 2, 3, 0]), None);
809        assert_eq!(trivial_merge(&[0, 1, 2, 3, 1]), None);
810        assert_eq!(trivial_merge(&[0, 1, 2, 3, 2]), None);
811        assert_eq!(trivial_merge(&[0, 1, 2, 3, 3]), None);
812        assert_eq!(trivial_merge(&[0, 1, 2, 3, 4]), None);
813    }
814
815    #[test]
816    fn test_legacy_form_conversion() {
817        fn test_equivalent<T>(legacy_form: (Vec<T>, Vec<T>), merge: Merge<Option<T>>)
818        where
819            T: Clone + PartialEq + std::fmt::Debug,
820        {
821            assert_eq!(merge.clone().into_legacy_form(), legacy_form);
822            assert_eq!(Merge::from_legacy_form(legacy_form.0, legacy_form.1), merge);
823        }
824        // Non-conflict
825        test_equivalent(
826            (vec![], vec![0]),
827            Merge::from_removes_adds(vec![], vec![Some(0)]),
828        );
829        // Regular 3-way conflict
830        test_equivalent(
831            (vec![0], vec![1, 2]),
832            Merge::from_removes_adds(vec![Some(0)], vec![Some(1), Some(2)]),
833        );
834        // Modify/delete conflict
835        test_equivalent(
836            (vec![0], vec![1]),
837            Merge::from_removes_adds(vec![Some(0)], vec![Some(1), None]),
838        );
839        // Add/add conflict
840        test_equivalent(
841            (vec![], vec![0, 1]),
842            Merge::from_removes_adds(vec![None], vec![Some(0), Some(1)]),
843        );
844        // 5-way conflict
845        test_equivalent(
846            (vec![0, 1], vec![2, 3, 4]),
847            Merge::from_removes_adds(vec![Some(0), Some(1)], vec![Some(2), Some(3), Some(4)]),
848        );
849        // 5-way delete/delete conflict
850        test_equivalent(
851            (vec![0, 1], vec![]),
852            Merge::from_removes_adds(vec![Some(0), Some(1)], vec![None, None, None]),
853        );
854    }
855
856    #[test]
857    fn test_as_resolved() {
858        assert_eq!(
859            Merge::from_removes_adds(vec![], vec![0]).as_resolved(),
860            Some(&0)
861        );
862        // Even a trivially resolvable merge is not resolved
863        assert_eq!(
864            Merge::from_removes_adds(vec![0], vec![0, 1]).as_resolved(),
865            None
866        );
867    }
868
869    #[test]
870    fn test_get_simplified_mapping() {
871        // 1-way merge
872        assert_eq!(c(&[0]).get_simplified_mapping(), vec![0]);
873        // 3-way merge
874        assert_eq!(c(&[0, 0, 0]).get_simplified_mapping(), vec![2]);
875        assert_eq!(c(&[0, 0, 1]).get_simplified_mapping(), vec![2]);
876        assert_eq!(c(&[0, 1, 0]).get_simplified_mapping(), vec![0, 1, 2]);
877        assert_eq!(c(&[0, 1, 1]).get_simplified_mapping(), vec![0]);
878        assert_eq!(c(&[0, 1, 2]).get_simplified_mapping(), vec![0, 1, 2]);
879        // 5-way merge
880        assert_eq!(c(&[0, 0, 0, 0, 0]).get_simplified_mapping(), vec![4]);
881        assert_eq!(c(&[0, 0, 0, 0, 1]).get_simplified_mapping(), vec![4]);
882        assert_eq!(c(&[0, 0, 0, 1, 0]).get_simplified_mapping(), vec![2, 3, 4]);
883        assert_eq!(c(&[0, 0, 0, 1, 1]).get_simplified_mapping(), vec![2]);
884        assert_eq!(c(&[0, 0, 0, 1, 2]).get_simplified_mapping(), vec![2, 3, 4]);
885        assert_eq!(c(&[0, 0, 1, 0, 0]).get_simplified_mapping(), vec![2]);
886        assert_eq!(c(&[0, 0, 1, 0, 1]).get_simplified_mapping(), vec![2, 3, 4]);
887        assert_eq!(c(&[0, 0, 1, 0, 2]).get_simplified_mapping(), vec![2, 3, 4]);
888        assert_eq!(c(&[0, 0, 1, 1, 0]).get_simplified_mapping(), vec![4]);
889        assert_eq!(c(&[0, 0, 1, 1, 1]).get_simplified_mapping(), vec![4]);
890        assert_eq!(c(&[0, 0, 1, 1, 2]).get_simplified_mapping(), vec![4]);
891        assert_eq!(c(&[0, 0, 2, 1, 0]).get_simplified_mapping(), vec![2, 3, 4]);
892        assert_eq!(c(&[0, 0, 2, 1, 1]).get_simplified_mapping(), vec![2]);
893        assert_eq!(c(&[0, 0, 2, 1, 2]).get_simplified_mapping(), vec![2, 3, 4]);
894        assert_eq!(c(&[0, 0, 2, 1, 3]).get_simplified_mapping(), vec![2, 3, 4]);
895        assert_eq!(c(&[0, 1, 0, 0, 0]).get_simplified_mapping(), vec![4, 1, 2]);
896        assert_eq!(c(&[0, 1, 0, 0, 1]).get_simplified_mapping(), vec![2]);
897        assert_eq!(c(&[0, 1, 0, 0, 2]).get_simplified_mapping(), vec![4, 1, 2]);
898        assert_eq!(
899            c(&[0, 1, 0, 1, 0]).get_simplified_mapping(),
900            vec![0, 1, 2, 3, 4]
901        );
902        assert_eq!(c(&[0, 1, 0, 1, 1]).get_simplified_mapping(), vec![0, 3, 2]);
903        assert_eq!(
904            c(&[0, 1, 0, 1, 2]).get_simplified_mapping(),
905            vec![0, 1, 2, 3, 4]
906        );
907        assert_eq!(
908            c(&[0, 1, 0, 2, 0]).get_simplified_mapping(),
909            vec![0, 1, 2, 3, 4]
910        );
911        assert_eq!(c(&[0, 1, 0, 2, 1]).get_simplified_mapping(), vec![0, 3, 2]);
912        assert_eq!(c(&[0, 1, 0, 2, 2]).get_simplified_mapping(), vec![0, 1, 2]);
913        assert_eq!(
914            c(&[0, 1, 0, 2, 3]).get_simplified_mapping(),
915            vec![0, 1, 2, 3, 4]
916        );
917        assert_eq!(c(&[0, 1, 1, 0, 0]).get_simplified_mapping(), vec![4]);
918        assert_eq!(c(&[0, 1, 1, 0, 1]).get_simplified_mapping(), vec![2]);
919        assert_eq!(c(&[0, 1, 1, 0, 2]).get_simplified_mapping(), vec![4]);
920        assert_eq!(c(&[0, 1, 1, 1, 0]).get_simplified_mapping(), vec![0, 3, 4]);
921        assert_eq!(c(&[0, 1, 1, 1, 1]).get_simplified_mapping(), vec![0]);
922        assert_eq!(c(&[0, 1, 1, 1, 2]).get_simplified_mapping(), vec![0, 3, 4]);
923        assert_eq!(c(&[0, 1, 1, 2, 0]).get_simplified_mapping(), vec![0, 3, 4]);
924        assert_eq!(c(&[0, 1, 1, 2, 1]).get_simplified_mapping(), vec![0, 3, 4]);
925        assert_eq!(c(&[0, 1, 1, 2, 2]).get_simplified_mapping(), vec![0]);
926        assert_eq!(c(&[0, 1, 1, 2, 3]).get_simplified_mapping(), vec![0, 3, 4]);
927        assert_eq!(c(&[0, 1, 2, 0, 0]).get_simplified_mapping(), vec![4, 1, 2]);
928        assert_eq!(c(&[0, 1, 2, 0, 1]).get_simplified_mapping(), vec![2]);
929        assert_eq!(c(&[0, 1, 2, 0, 2]).get_simplified_mapping(), vec![4, 1, 2]);
930        assert_eq!(c(&[0, 1, 2, 0, 3]).get_simplified_mapping(), vec![4, 1, 2]);
931        assert_eq!(
932            c(&[0, 1, 2, 1, 0]).get_simplified_mapping(),
933            vec![0, 1, 2, 3, 4]
934        );
935        assert_eq!(c(&[0, 1, 2, 1, 1]).get_simplified_mapping(), vec![0, 3, 2]);
936        assert_eq!(
937            c(&[0, 1, 2, 1, 2]).get_simplified_mapping(),
938            vec![0, 1, 2, 3, 4]
939        );
940        assert_eq!(
941            c(&[0, 1, 2, 1, 3]).get_simplified_mapping(),
942            vec![0, 1, 2, 3, 4]
943        );
944        assert_eq!(c(&[0, 1, 2, 2, 0]).get_simplified_mapping(), vec![0, 1, 4]);
945        assert_eq!(c(&[0, 1, 2, 2, 1]).get_simplified_mapping(), vec![0]);
946        assert_eq!(c(&[0, 1, 2, 2, 2]).get_simplified_mapping(), vec![0, 1, 4]);
947        assert_eq!(c(&[0, 1, 2, 2, 3]).get_simplified_mapping(), vec![0, 1, 4]);
948        assert_eq!(
949            c(&[0, 1, 2, 3, 0]).get_simplified_mapping(),
950            vec![0, 1, 2, 3, 4]
951        );
952        assert_eq!(c(&[0, 1, 2, 3, 1]).get_simplified_mapping(), vec![0, 3, 2]);
953        assert_eq!(
954            c(&[0, 1, 2, 3, 2]).get_simplified_mapping(),
955            vec![0, 1, 2, 3, 4]
956        );
957        assert_eq!(
958            c(&[0, 1, 2, 3, 4, 5, 1]).get_simplified_mapping(),
959            vec![0, 3, 4, 5, 2]
960        );
961        assert_eq!(
962            c(&[0, 1, 2, 3, 4]).get_simplified_mapping(),
963            vec![0, 1, 2, 3, 4]
964        );
965        assert_eq!(c(&[2, 0, 3, 1, 1]).get_simplified_mapping(), vec![0, 1, 2]);
966    }
967
968    #[test]
969    fn test_simplify() {
970        // 1-way merge
971        assert_eq!(c(&[0]).simplify(), c(&[0]));
972        // 3-way merge
973        assert_eq!(c(&[0, 0, 0]).simplify(), c(&[0]));
974        assert_eq!(c(&[0, 0, 1]).simplify(), c(&[1]));
975        assert_eq!(c(&[1, 0, 0]).simplify(), c(&[1]));
976        assert_eq!(c(&[1, 0, 1]).simplify(), c(&[1, 0, 1]));
977        assert_eq!(c(&[1, 0, 2]).simplify(), c(&[1, 0, 2]));
978        // 5-way merge
979        assert_eq!(c(&[0, 0, 0, 0, 0]).simplify(), c(&[0]));
980        assert_eq!(c(&[0, 0, 0, 0, 1]).simplify(), c(&[1]));
981        assert_eq!(c(&[0, 0, 0, 1, 0]).simplify(), c(&[0, 1, 0]));
982        assert_eq!(c(&[0, 0, 0, 1, 1]).simplify(), c(&[0]));
983        assert_eq!(c(&[0, 0, 0, 1, 2]).simplify(), c(&[0, 1, 2]));
984        assert_eq!(c(&[0, 0, 1, 0, 0]).simplify(), c(&[1]));
985        assert_eq!(c(&[0, 0, 1, 0, 1]).simplify(), c(&[1, 0, 1]));
986        assert_eq!(c(&[0, 0, 1, 0, 2]).simplify(), c(&[1, 0, 2]));
987        assert_eq!(c(&[0, 0, 1, 1, 0]).simplify(), c(&[0]));
988        assert_eq!(c(&[0, 0, 1, 1, 1]).simplify(), c(&[1]));
989        assert_eq!(c(&[0, 0, 1, 1, 2]).simplify(), c(&[2]));
990        assert_eq!(c(&[0, 0, 2, 1, 0]).simplify(), c(&[2, 1, 0]));
991        assert_eq!(c(&[0, 0, 2, 1, 1]).simplify(), c(&[2]));
992        assert_eq!(c(&[0, 0, 2, 1, 2]).simplify(), c(&[2, 1, 2]));
993        assert_eq!(c(&[0, 0, 2, 1, 3]).simplify(), c(&[2, 1, 3]));
994        assert_eq!(c(&[0, 1, 0, 0, 0]).simplify(), c(&[0, 1, 0]));
995        assert_eq!(c(&[0, 1, 0, 0, 1]).simplify(), c(&[0]));
996        assert_eq!(c(&[0, 1, 0, 0, 2]).simplify(), c(&[2, 1, 0]));
997        assert_eq!(c(&[0, 1, 0, 1, 0]).simplify(), c(&[0, 1, 0, 1, 0]));
998        assert_eq!(c(&[0, 1, 0, 1, 1]).simplify(), c(&[0, 1, 0]));
999        assert_eq!(c(&[0, 1, 0, 1, 2]).simplify(), c(&[0, 1, 0, 1, 2]));
1000        assert_eq!(c(&[0, 1, 0, 2, 0]).simplify(), c(&[0, 1, 0, 2, 0]));
1001        assert_eq!(c(&[0, 1, 0, 2, 1]).simplify(), c(&[0, 2, 0]));
1002        assert_eq!(c(&[0, 1, 0, 2, 2]).simplify(), c(&[0, 1, 0]));
1003        assert_eq!(c(&[0, 1, 0, 2, 3]).simplify(), c(&[0, 1, 0, 2, 3]));
1004        assert_eq!(c(&[0, 1, 1, 0, 0]).simplify(), c(&[0]));
1005        assert_eq!(c(&[0, 1, 1, 0, 1]).simplify(), c(&[1]));
1006        assert_eq!(c(&[0, 1, 1, 0, 2]).simplify(), c(&[2]));
1007        assert_eq!(c(&[0, 1, 1, 1, 0]).simplify(), c(&[0, 1, 0]));
1008        assert_eq!(c(&[0, 1, 1, 1, 1]).simplify(), c(&[0]));
1009        assert_eq!(c(&[0, 1, 1, 1, 2]).simplify(), c(&[0, 1, 2]));
1010        assert_eq!(c(&[0, 1, 1, 2, 0]).simplify(), c(&[0, 2, 0]));
1011        assert_eq!(c(&[0, 1, 1, 2, 1]).simplify(), c(&[0, 2, 1]));
1012        assert_eq!(c(&[0, 1, 1, 2, 2]).simplify(), c(&[0]));
1013        assert_eq!(c(&[0, 1, 1, 2, 3]).simplify(), c(&[0, 2, 3]));
1014        assert_eq!(c(&[0, 1, 2, 0, 0]).simplify(), c(&[0, 1, 2]));
1015        assert_eq!(c(&[0, 1, 2, 0, 1]).simplify(), c(&[2]));
1016        assert_eq!(c(&[0, 1, 2, 0, 2]).simplify(), c(&[2, 1, 2]));
1017        assert_eq!(c(&[0, 1, 2, 0, 3]).simplify(), c(&[3, 1, 2]));
1018        assert_eq!(c(&[0, 1, 2, 1, 0]).simplify(), c(&[0, 1, 2, 1, 0]));
1019        assert_eq!(c(&[0, 1, 2, 1, 1]).simplify(), c(&[0, 1, 2]));
1020        assert_eq!(c(&[0, 1, 2, 1, 2]).simplify(), c(&[0, 1, 2, 1, 2]));
1021        assert_eq!(c(&[0, 1, 2, 1, 3]).simplify(), c(&[0, 1, 2, 1, 3]));
1022        assert_eq!(c(&[0, 1, 2, 2, 0]).simplify(), c(&[0, 1, 0]));
1023        assert_eq!(c(&[0, 1, 2, 2, 1]).simplify(), c(&[0]));
1024        assert_eq!(c(&[0, 1, 2, 2, 2]).simplify(), c(&[0, 1, 2]));
1025        assert_eq!(c(&[0, 1, 2, 2, 3]).simplify(), c(&[0, 1, 3]));
1026        assert_eq!(c(&[0, 1, 2, 3, 0]).simplify(), c(&[0, 1, 2, 3, 0]));
1027        assert_eq!(c(&[0, 1, 2, 3, 1]).simplify(), c(&[0, 3, 2]));
1028        assert_eq!(c(&[0, 1, 2, 3, 2]).simplify(), c(&[0, 1, 2, 3, 2]));
1029        assert_eq!(c(&[0, 1, 2, 3, 3]).simplify(), c(&[0, 1, 2]));
1030        assert_eq!(c(&[0, 1, 2, 3, 4]).simplify(), c(&[0, 1, 2, 3, 4]));
1031        assert_eq!(c(&[0, 1, 2, 3, 4, 5, 1]).simplify(), c(&[0, 3, 4, 5, 2]));
1032    }
1033
1034    #[test]
1035    fn test_update_from_simplified() {
1036        // 1-way merge
1037        assert_eq!(c(&[0]).update_from_simplified(c(&[1])), c(&[1]));
1038        // 3-way merge
1039        assert_eq!(c(&[0, 0, 0]).update_from_simplified(c(&[1])), c(&[0, 0, 1]));
1040        assert_eq!(c(&[1, 0, 0]).update_from_simplified(c(&[2])), c(&[2, 0, 0]));
1041        assert_eq!(
1042            c(&[1, 0, 2]).update_from_simplified(c(&[2, 1, 3])),
1043            c(&[2, 1, 3])
1044        );
1045        // 5-way merge
1046        assert_eq!(
1047            c(&[0, 0, 0, 0, 0]).update_from_simplified(c(&[1])),
1048            c(&[0, 0, 0, 0, 1])
1049        );
1050        assert_eq!(
1051            c(&[0, 0, 0, 1, 0]).update_from_simplified(c(&[2, 3, 1])),
1052            c(&[0, 0, 2, 3, 1])
1053        );
1054        assert_eq!(
1055            c(&[0, 1, 0, 0, 0]).update_from_simplified(c(&[2, 3, 1])),
1056            c(&[0, 3, 1, 0, 2])
1057        );
1058        assert_eq!(
1059            c(&[2, 0, 3, 1, 4]).update_from_simplified(c(&[3, 1, 4, 2, 5])),
1060            c(&[3, 1, 4, 2, 5])
1061        );
1062
1063        assert_eq!(c(&[0, 0, 3, 1, 3, 2, 4]).simplify(), c(&[3, 1, 3, 2, 4]));
1064        // Check that the `3`s are replaced correctly and that `4` ends up in the
1065        // correct position.
1066        assert_eq!(
1067            c(&[0, 0, 3, 1, 3, 2, 4]).update_from_simplified(c(&[10, 1, 11, 2, 4])),
1068            c(&[0, 0, 10, 1, 11, 2, 4])
1069        );
1070    }
1071
1072    #[test]
1073    fn test_merge_invariants() {
1074        fn check_invariants(terms: &[u32]) {
1075            let merge = Merge::from_vec(terms.to_vec());
1076            // `simplify()` is idempotent
1077            assert_eq!(
1078                merge.simplify().simplify(),
1079                merge.simplify(),
1080                "simplify() not idempotent for {merge:?}"
1081            );
1082            // `resolve_trivial()` is unaffected by `simplify()`
1083            assert_eq!(
1084                merge.simplify().resolve_trivial(),
1085                merge.resolve_trivial(),
1086                "simplify() changed result of resolve_trivial() for {merge:?}"
1087            );
1088        }
1089        // 1-way merge
1090        check_invariants(&[0]);
1091        for i in 0..=1 {
1092            for j in 0..=i + 1 {
1093                // 3-way merge
1094                check_invariants(&[i, 0, j]);
1095                for k in 0..=j + 1 {
1096                    for l in 0..=k + 1 {
1097                        // 5-way merge
1098                        check_invariants(&[0, i, j, k, l]);
1099                    }
1100                }
1101            }
1102        }
1103    }
1104
1105    #[test]
1106    fn test_swap_remove() {
1107        let mut x = c(&[0, 1, 2, 3, 4, 5, 6]);
1108        assert_eq!(x.swap_remove(0, 1), (1, 2));
1109        assert_eq!(x, c(&[0, 5, 6, 3, 4]));
1110        assert_eq!(x.swap_remove(1, 0), (3, 0));
1111        assert_eq!(x, c(&[4, 5, 6]));
1112        assert_eq!(x.swap_remove(0, 1), (5, 6));
1113        assert_eq!(x, c(&[4]));
1114    }
1115
1116    #[test]
1117    fn test_pad_to() {
1118        let mut x = c(&[1]);
1119        x.pad_to(3, &2);
1120        assert_eq!(x, c(&[1, 2, 2, 2, 2]));
1121        // No change if the requested size is smaller
1122        x.pad_to(1, &3);
1123        assert_eq!(x, c(&[1, 2, 2, 2, 2]));
1124    }
1125
1126    #[test]
1127    fn test_iter() {
1128        // 1-way merge
1129        assert_eq!(c(&[1]).iter().collect_vec(), vec![&1]);
1130        // 5-way merge
1131        assert_eq!(
1132            c(&[1, 2, 3, 4, 5]).iter().collect_vec(),
1133            vec![&1, &2, &3, &4, &5]
1134        );
1135    }
1136
1137    #[test]
1138    fn test_from_iter() {
1139        // 1-way merge
1140        assert_eq!(MergeBuilder::from_iter([1]).build(), c(&[1]));
1141        // 5-way merge
1142        assert_eq!(
1143            MergeBuilder::from_iter([1, 2, 3, 4, 5]).build(),
1144            c(&[1, 2, 3, 4, 5])
1145        );
1146    }
1147
1148    #[test]
1149    #[should_panic]
1150    fn test_from_iter_empty() {
1151        MergeBuilder::from_iter([1; 0]).build();
1152    }
1153
1154    #[test]
1155    #[should_panic]
1156    fn test_from_iter_even() {
1157        MergeBuilder::from_iter([1, 2]).build();
1158    }
1159
1160    #[test]
1161    fn test_extend() {
1162        // 1-way merge
1163        let mut builder: MergeBuilder<i32> = Default::default();
1164        builder.extend([1]);
1165        assert_eq!(builder.build(), c(&[1]));
1166        // 5-way merge
1167        let mut builder: MergeBuilder<i32> = Default::default();
1168        builder.extend([1, 2]);
1169        builder.extend([3, 4, 5]);
1170        assert_eq!(builder.build(), c(&[1, 2, 3, 4, 5]));
1171    }
1172
1173    #[test]
1174    fn test_map() {
1175        fn increment(i: &i32) -> i32 {
1176            i + 1
1177        }
1178        // 1-way merge
1179        assert_eq!(c(&[1]).map(increment), c(&[2]));
1180        // 3-way merge
1181        assert_eq!(c(&[1, 3, 5]).map(increment), c(&[2, 4, 6]));
1182    }
1183
1184    #[test]
1185    fn test_try_map() {
1186        fn sqrt(i: &i32) -> Result<i32, ()> {
1187            if *i >= 0 {
1188                Ok((*i as f64).sqrt() as i32)
1189            } else {
1190                Err(())
1191            }
1192        }
1193        // 1-way merge
1194        assert_eq!(c(&[1]).try_map(sqrt), Ok(c(&[1])));
1195        assert_eq!(c(&[-1]).try_map(sqrt), Err(()));
1196        // 3-way merge
1197        assert_eq!(c(&[1, 4, 9]).try_map(sqrt), Ok(c(&[1, 2, 3])));
1198        assert_eq!(c(&[-1, 4, 9]).try_map(sqrt), Err(()));
1199        assert_eq!(c(&[1, -4, 9]).try_map(sqrt), Err(()));
1200    }
1201
1202    #[test]
1203    fn test_flatten() {
1204        // 1-way merge of 1-way merge
1205        assert_eq!(c(&[c(&[0])]).flatten(), c(&[0]));
1206        // 1-way merge of 3-way merge
1207        assert_eq!(c(&[c(&[0, 1, 2])]).flatten(), c(&[0, 1, 2]));
1208        // 3-way merge of 1-way merges
1209        assert_eq!(c(&[c(&[0]), c(&[1]), c(&[2])]).flatten(), c(&[0, 1, 2]));
1210        // 3-way merge of 3-way merges
1211        assert_eq!(
1212            c(&[c(&[0, 1, 2]), c(&[3, 4, 5]), c(&[6, 7, 8])]).flatten(),
1213            c(&[0, 1, 2, 5, 4, 3, 6, 7, 8])
1214        );
1215    }
1216}