From 07dbc9fb0d2b3825ed39444b45009c18a23eeb4e Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Thu, 29 Jun 2023 06:50:23 -0700 Subject: [PATCH] conflicts: add `flatten()` for flattening nested conflicts --- lib/src/conflicts.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/lib/src/conflicts.rs b/lib/src/conflicts.rs index c1affd47f..544273b39 100644 --- a/lib/src/conflicts.rs +++ b/lib/src/conflicts.rs @@ -164,6 +164,40 @@ impl Conflict> { } } +impl Conflict> { + /// Flattens a nested conflict into a regular conflict. + /// + /// Let's say we have a 3-way merge of 3-way merges like this: + /// + /// 4 5 7 8 + /// 3 6 + /// 1 2 + /// 0 + /// + /// Flattening that results in this 9-way conflict: + /// + /// 4 5 0 7 8 + /// 3 2 1 6 + pub fn flatten(mut self) -> Conflict { + self.removes.reverse(); + self.adds.reverse(); + let mut result = self.adds.pop().unwrap(); + while let Some(mut remove) = self.removes.pop() { + // Add removes reversed, and with the first element moved last, so we preserve + // the diffs + let first_add = remove.adds.remove(0); + result.removes.extend(remove.adds); + result.removes.push(first_add); + result.adds.extend(remove.removes); + let add = self.adds.pop().unwrap(); + result.removes.extend(add.removes); + result.adds.extend(add.adds); + } + assert!(self.adds.is_empty()); + result + } +} + impl Conflict> { /// Create a `Conflict` from a `backend::Conflict`, padding with `None` to /// make sure that there is exactly one more `adds()` than `removes()`. @@ -820,4 +854,25 @@ mod tests { assert_eq!(c(&[-1], &[4, 9]).try_map(sqrt), Err(())); assert_eq!(c(&[1], &[-4, 9]).try_map(sqrt), Err(())); } + + #[test] + fn test_flatten() { + fn c(removes: &[T], adds: &[T]) -> Conflict { + Conflict::new(removes.to_vec(), adds.to_vec()) + } + // 1-way conflict of 1-way conflict + assert_eq!(c(&[], &[c(&[], &[0])]).flatten(), c(&[], &[0])); + // 1-way conflict of 3-way conflict + assert_eq!(c(&[], &[c(&[0], &[1, 2])]).flatten(), c(&[0], &[1, 2])); + // 3-way conflict of 1-way conflicts + assert_eq!( + c(&[c(&[], &[0])], &[c(&[], &[1]), c(&[], &[2])]).flatten(), + c(&[0], &[1, 2]) + ); + // 3-way conflict of 3-way conflicts + assert_eq!( + c(&[c(&[0], &[1, 2])], &[c(&[3], &[4, 5]), c(&[6], &[7, 8])]).flatten(), + c(&[3, 2, 1, 6], &[4, 5, 0, 7, 8]) + ); + } }