multi_buffer: Refactor diff_transforms field into a separate struct (#32237)

Piotr Osiewicz created

A minor refactor ~needed to unblock #22546; it's pretty hard to add an
extra field to `diff_transforms` dimension, as it is a 2-tuple (which
uses a blanket impl)

Release Notes:

- N/A

Change summary

crates/multi_buffer/src/multi_buffer.rs | 152 +++++++++++++++++---------
1 file changed, 98 insertions(+), 54 deletions(-)

Detailed changes

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -43,7 +43,7 @@ use std::{
     sync::Arc,
     time::{Duration, Instant},
 };
-use sum_tree::{Bias, Cursor, SumTree, TreeMap};
+use sum_tree::{Bias, Cursor, Dimension, SumTree, Summary, TreeMap};
 use text::{
     BufferId, Edit, LineIndent, TextSummary,
     locator::Locator,
@@ -417,8 +417,7 @@ struct Excerpt {
 #[derive(Clone)]
 pub struct MultiBufferExcerpt<'a> {
     excerpt: &'a Excerpt,
-    diff_transforms:
-        sum_tree::Cursor<'a, DiffTransform, (OutputDimension<usize>, ExcerptDimension<usize>)>,
+    diff_transforms: sum_tree::Cursor<'a, DiffTransform, DiffTransforms<usize>>,
     offset: usize,
     excerpt_offset: ExcerptDimension<usize>,
     buffer_offset: usize,
@@ -506,10 +505,36 @@ pub struct ReversedMultiBufferBytes<'a> {
     chunk: &'a [u8],
 }
 
+#[derive(Clone)]
+struct DiffTransforms<D> {
+    output_dimension: OutputDimension<D>,
+    excerpt_dimension: ExcerptDimension<D>,
+}
+
+impl<'a, D: TextDimension> Dimension<'a, DiffTransformSummary> for DiffTransforms<D> {
+    fn zero(cx: &<DiffTransformSummary as sum_tree::Summary>::Context) -> Self {
+        Self {
+            output_dimension: OutputDimension::zero(cx),
+            excerpt_dimension: <ExcerptDimension<D> as Dimension<'a, DiffTransformSummary>>::zero(
+                cx,
+            ),
+        }
+    }
+
+    fn add_summary(
+        &mut self,
+        summary: &'a DiffTransformSummary,
+        cx: &<DiffTransformSummary as sum_tree::Summary>::Context,
+    ) {
+        self.output_dimension.add_summary(summary, cx);
+        self.excerpt_dimension.add_summary(summary, cx);
+    }
+}
+
 #[derive(Clone)]
 struct MultiBufferCursor<'a, D: TextDimension> {
     excerpts: Cursor<'a, Excerpt, ExcerptDimension<D>>,
-    diff_transforms: Cursor<'a, DiffTransform, (OutputDimension<D>, ExcerptDimension<D>)>,
+    diff_transforms: Cursor<'a, DiffTransform, DiffTransforms<D>>,
     diffs: &'a TreeMap<BufferId, BufferDiffSnapshot>,
     cached_region: Option<MultiBufferRegion<'a, D>>,
 }
@@ -5267,18 +5292,16 @@ impl MultiBufferSnapshot {
         excerpts.seek(&Some(start_locator), Bias::Left, &());
         excerpts.prev(&());
 
-        let mut diff_transforms = self
-            .diff_transforms
-            .cursor::<(OutputDimension<usize>, ExcerptDimension<usize>)>(&());
+        let mut diff_transforms = self.diff_transforms.cursor::<DiffTransforms<usize>>(&());
         diff_transforms.seek(&excerpts.start().1, Bias::Left, &());
-        if diff_transforms.end(&()).1 < excerpts.start().1 {
+        if diff_transforms.end(&()).excerpt_dimension < excerpts.start().1 {
             diff_transforms.next(&());
         }
 
         let excerpt = excerpts.item()?;
         Some(MultiBufferExcerpt {
             excerpt,
-            offset: diff_transforms.start().0.0,
+            offset: diff_transforms.start().output_dimension.0,
             buffer_offset: excerpt.range.context.start.to_offset(&excerpt.buffer),
             excerpt_offset: excerpts.start().1.clone(),
             diff_transforms,
@@ -6386,13 +6409,15 @@ where
         self.cached_region.take();
         self.diff_transforms
             .seek(&OutputDimension(*position), Bias::Right, &());
-        if self.diff_transforms.item().is_none() && *position == self.diff_transforms.start().0.0 {
+        if self.diff_transforms.item().is_none()
+            && *position == self.diff_transforms.start().output_dimension.0
+        {
             self.diff_transforms.prev(&());
         }
 
-        let mut excerpt_position = self.diff_transforms.start().1.0;
+        let mut excerpt_position = self.diff_transforms.start().excerpt_dimension.0;
         if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
-            let overshoot = *position - self.diff_transforms.start().0.0;
+            let overshoot = *position - self.diff_transforms.start().output_dimension.0;
             excerpt_position.add_assign(&overshoot);
         }
 
@@ -6407,12 +6432,14 @@ where
         self.cached_region.take();
         self.diff_transforms
             .seek_forward(&OutputDimension(*position), Bias::Right, &());
-        if self.diff_transforms.item().is_none() && *position == self.diff_transforms.start().0.0 {
+        if self.diff_transforms.item().is_none()
+            && *position == self.diff_transforms.start().output_dimension.0
+        {
             self.diff_transforms.prev(&());
         }
 
-        let overshoot = *position - self.diff_transforms.start().0.0;
-        let mut excerpt_position = self.diff_transforms.start().1.0;
+        let overshoot = *position - self.diff_transforms.start().output_dimension.0;
+        let mut excerpt_position = self.diff_transforms.start().excerpt_dimension.0;
         if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
             excerpt_position.add_assign(&overshoot);
         }
@@ -6438,8 +6465,8 @@ where
         self.cached_region.take();
         self.diff_transforms
             .seek(self.excerpts.start(), Bias::Left, &());
-        if self.diff_transforms.end(&()).1 == *self.excerpts.start()
-            && self.diff_transforms.start().1 < *self.excerpts.start()
+        if self.diff_transforms.end(&()).excerpt_dimension == *self.excerpts.start()
+            && self.diff_transforms.start().excerpt_dimension < *self.excerpts.start()
             && self.diff_transforms.next_item().is_some()
         {
             self.diff_transforms.next(&());
@@ -6448,12 +6475,17 @@ where
 
     fn next(&mut self) {
         self.cached_region.take();
-        match self.diff_transforms.end(&()).1.cmp(&self.excerpts.end(&())) {
+        match self
+            .diff_transforms
+            .end(&())
+            .excerpt_dimension
+            .cmp(&self.excerpts.end(&()))
+        {
             cmp::Ordering::Less => self.diff_transforms.next(&()),
             cmp::Ordering::Greater => self.excerpts.next(&()),
             cmp::Ordering::Equal => {
                 self.diff_transforms.next(&());
-                if self.diff_transforms.end(&()).1 > self.excerpts.end(&())
+                if self.diff_transforms.end(&()).excerpt_dimension > self.excerpts.end(&())
                     || self.diff_transforms.item().is_none()
                 {
                     self.excerpts.next(&());
@@ -6474,12 +6506,17 @@ where
 
     fn prev(&mut self) {
         self.cached_region.take();
-        match self.diff_transforms.start().1.cmp(self.excerpts.start()) {
+        match self
+            .diff_transforms
+            .start()
+            .excerpt_dimension
+            .cmp(self.excerpts.start())
+        {
             cmp::Ordering::Less => self.excerpts.prev(&()),
             cmp::Ordering::Greater => self.diff_transforms.prev(&()),
             cmp::Ordering::Equal => {
                 self.diff_transforms.prev(&());
-                if self.diff_transforms.start().1 < *self.excerpts.start()
+                if self.diff_transforms.start().excerpt_dimension < *self.excerpts.start()
                     || self.diff_transforms.item().is_none()
                 {
                     self.excerpts.prev(&());
@@ -6496,9 +6533,9 @@ where
     }
 
     fn is_at_start_of_excerpt(&mut self) -> bool {
-        if self.diff_transforms.start().1 > *self.excerpts.start() {
+        if self.diff_transforms.start().excerpt_dimension > *self.excerpts.start() {
             return false;
-        } else if self.diff_transforms.start().1 < *self.excerpts.start() {
+        } else if self.diff_transforms.start().excerpt_dimension < *self.excerpts.start() {
             return true;
         }
 
@@ -6512,9 +6549,9 @@ where
     }
 
     fn is_at_end_of_excerpt(&mut self) -> bool {
-        if self.diff_transforms.end(&()).1 < self.excerpts.end(&()) {
+        if self.diff_transforms.end(&()).excerpt_dimension < self.excerpts.end(&()) {
             return false;
-        } else if self.diff_transforms.end(&()).1 > self.excerpts.end(&())
+        } else if self.diff_transforms.end(&()).excerpt_dimension > self.excerpts.end(&())
             || self.diff_transforms.item().is_none()
         {
             return true;
@@ -6535,7 +6572,7 @@ where
         let buffer = &excerpt.buffer;
         let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
         let mut buffer_start = buffer_context_start;
-        let overshoot = self.diff_transforms.end(&()).1.0 - self.excerpts.start().0;
+        let overshoot = self.diff_transforms.end(&()).excerpt_dimension.0 - self.excerpts.start().0;
         buffer_start.add_assign(&overshoot);
         Some(buffer_start)
     }
@@ -6557,8 +6594,8 @@ where
                 let buffer_range_len = rope_cursor.summary::<D>(base_text_byte_range.end);
                 let mut buffer_end = buffer_start;
                 buffer_end.add_assign(&buffer_range_len);
-                let start = self.diff_transforms.start().0.0;
-                let end = self.diff_transforms.end(&()).0.0;
+                let start = self.diff_transforms.start().output_dimension.0;
+                let end = self.diff_transforms.end(&()).output_dimension.0;
                 return Some(MultiBufferRegion {
                     buffer,
                     excerpt,
@@ -6577,28 +6614,32 @@ where
                 let buffer = &excerpt.buffer;
                 let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
 
-                let mut start = self.diff_transforms.start().0.0;
+                let mut start = self.diff_transforms.start().output_dimension.0;
                 let mut buffer_start = buffer_context_start;
-                if self.diff_transforms.start().1 < *self.excerpts.start() {
-                    let overshoot = self.excerpts.start().0 - self.diff_transforms.start().1.0;
+                if self.diff_transforms.start().excerpt_dimension < *self.excerpts.start() {
+                    let overshoot =
+                        self.excerpts.start().0 - self.diff_transforms.start().excerpt_dimension.0;
                     start.add_assign(&overshoot);
                 } else {
-                    let overshoot = self.diff_transforms.start().1.0 - self.excerpts.start().0;
+                    let overshoot =
+                        self.diff_transforms.start().excerpt_dimension.0 - self.excerpts.start().0;
                     buffer_start.add_assign(&overshoot);
                 }
 
                 let mut end;
                 let mut buffer_end;
                 let has_trailing_newline;
-                if self.diff_transforms.end(&()).1.0 < self.excerpts.end(&()).0 {
-                    let overshoot = self.diff_transforms.end(&()).1.0 - self.excerpts.start().0;
-                    end = self.diff_transforms.end(&()).0.0;
+                if self.diff_transforms.end(&()).excerpt_dimension.0 < self.excerpts.end(&()).0 {
+                    let overshoot =
+                        self.diff_transforms.end(&()).excerpt_dimension.0 - self.excerpts.start().0;
+                    end = self.diff_transforms.end(&()).output_dimension.0;
                     buffer_end = buffer_context_start;
                     buffer_end.add_assign(&overshoot);
                     has_trailing_newline = false;
                 } else {
-                    let overshoot = self.excerpts.end(&()).0 - self.diff_transforms.start().1.0;
-                    end = self.diff_transforms.start().0.0;
+                    let overshoot =
+                        self.excerpts.end(&()).0 - self.diff_transforms.start().excerpt_dimension.0;
+                    end = self.diff_transforms.start().output_dimension.0;
                     end.add_assign(&overshoot);
                     buffer_end = excerpt.range.context.end.summary::<D>(buffer);
                     has_trailing_newline = excerpt.has_trailing_newline;
@@ -6994,9 +7035,9 @@ impl<'a> MultiBufferExcerpt<'a> {
     }
 
     fn map_offset_to_buffer_internal(&self, offset: usize) -> usize {
-        let mut excerpt_offset = self.diff_transforms.start().1.clone();
+        let mut excerpt_offset = self.diff_transforms.start().excerpt_dimension.clone();
         if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
-            excerpt_offset.0 += offset - self.diff_transforms.start().0.0;
+            excerpt_offset.0 += offset - self.diff_transforms.start().output_dimension.0;
         };
         let offset_in_excerpt = excerpt_offset.0.saturating_sub(self.excerpt_offset.0);
         self.buffer_offset + offset_in_excerpt
@@ -7019,22 +7060,22 @@ impl<'a> MultiBufferExcerpt<'a> {
         let overshoot = buffer_range.start - self.buffer_offset;
         let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
         self.diff_transforms.seek(&excerpt_offset, Bias::Right, &());
-        if excerpt_offset.0 < self.diff_transforms.start().1.0 {
+        if excerpt_offset.0 < self.diff_transforms.start().excerpt_dimension.0 {
             log::warn!(
                 "Attempting to map a range from a buffer offset that starts before the current buffer offset"
             );
             return buffer_range;
         }
-        let overshoot = excerpt_offset.0 - self.diff_transforms.start().1.0;
-        let start = self.diff_transforms.start().0.0 + overshoot;
+        let overshoot = excerpt_offset.0 - self.diff_transforms.start().excerpt_dimension.0;
+        let start = self.diff_transforms.start().output_dimension.0 + overshoot;
 
         let end = if buffer_range.end > buffer_range.start {
             let overshoot = buffer_range.end - self.buffer_offset;
             let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
             self.diff_transforms
                 .seek_forward(&excerpt_offset, Bias::Right, &());
-            let overshoot = excerpt_offset.0 - self.diff_transforms.start().1.0;
-            self.diff_transforms.start().0.0 + overshoot
+            let overshoot = excerpt_offset.0 - self.diff_transforms.start().excerpt_dimension.0;
+            self.diff_transforms.start().output_dimension.0 + overshoot
         } else {
             start
         };
@@ -7201,7 +7242,7 @@ impl sum_tree::Summary for ExcerptSummary {
     fn add_summary(&mut self, summary: &Self, _: &()) {
         debug_assert!(summary.excerpt_locator > self.excerpt_locator);
         self.excerpt_locator = summary.excerpt_locator.clone();
-        self.text.add_summary(&summary.text, &());
+        Summary::add_summary(&mut self.text, &summary.text, &());
         self.widest_line_number = cmp::max(self.widest_line_number, summary.widest_line_number);
     }
 }
@@ -7310,16 +7351,11 @@ impl<D: TextDimension + Ord> sum_tree::SeekTarget<'_, DiffTransformSummary, Diff
     }
 }
 
-impl<D: TextDimension + Ord>
-    sum_tree::SeekTarget<'_, DiffTransformSummary, (OutputDimension<D>, ExcerptDimension<D>)>
+impl<D: TextDimension + Ord> sum_tree::SeekTarget<'_, DiffTransformSummary, DiffTransforms<D>>
     for ExcerptDimension<D>
 {
-    fn cmp(
-        &self,
-        cursor_location: &(OutputDimension<D>, ExcerptDimension<D>),
-        _: &(),
-    ) -> cmp::Ordering {
-        Ord::cmp(&self.0, &cursor_location.1.0)
+    fn cmp(&self, cursor_location: &DiffTransforms<D>, _: &()) -> cmp::Ordering {
+        Ord::cmp(&self.0, &cursor_location.excerpt_dimension.0)
     }
 }
 
@@ -7333,6 +7369,14 @@ impl<'a, D: TextDimension> sum_tree::Dimension<'a, DiffTransformSummary> for Exc
     }
 }
 
+impl<D: TextDimension + Ord> sum_tree::SeekTarget<'_, DiffTransformSummary, DiffTransforms<D>>
+    for OutputDimension<D>
+{
+    fn cmp(&self, cursor_location: &DiffTransforms<D>, _: &()) -> cmp::Ordering {
+        Ord::cmp(&self.0, &cursor_location.output_dimension.0)
+    }
+}
+
 impl<'a, D: TextDimension> sum_tree::Dimension<'a, DiffTransformSummary> for OutputDimension<D> {
     fn zero(_: &()) -> Self {
         OutputDimension(D::default())
@@ -7401,7 +7445,7 @@ impl Iterator for MultiBufferRows<'_> {
             if let Some(next_region) = self.cursor.region() {
                 region = next_region;
             } else {
-                if self.point == self.cursor.diff_transforms.end(&()).0.0 {
+                if self.point == self.cursor.diff_transforms.end(&()).output_dimension.0 {
                     let multibuffer_row = MultiBufferRow(self.point.row);
                     let last_excerpt = self
                         .cursor