diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index 479b31fe6c..c1789a933b 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -1,3 +1,5 @@ +use crate::FullOffset; + use super::{Buffer, Content, FromAnchor, Point, ToOffset}; use anyhow::Result; use std::{cmp::Ordering, ops::Range}; @@ -5,7 +7,7 @@ use sum_tree::{Bias, SumTree}; #[derive(Clone, Eq, PartialEq, Debug, Hash)] pub struct Anchor { - pub full_offset: usize, + pub full_offset: FullOffset, pub bias: Bias, pub version: clock::Global, } @@ -13,7 +15,7 @@ pub struct Anchor { #[derive(Clone)] pub struct AnchorMap { pub(crate) version: clock::Global, - pub(crate) entries: Vec<((usize, Bias), T)>, + pub(crate) entries: Vec<((FullOffset, Bias), T)>, } #[derive(Clone)] @@ -22,7 +24,7 @@ pub struct AnchorSet(pub(crate) AnchorMap<()>); #[derive(Clone)] pub struct AnchorRangeMap { pub(crate) version: clock::Global, - pub(crate) entries: Vec<(Range<(usize, Bias)>, T)>, + pub(crate) entries: Vec<(Range<(FullOffset, Bias)>, T)>, } #[derive(Clone)] @@ -44,23 +46,23 @@ pub(crate) struct AnchorRangeMultimapEntry { #[derive(Clone, Debug)] pub(crate) struct FullOffsetRange { - pub(crate) start: usize, - pub(crate) end: usize, + pub(crate) start: FullOffset, + pub(crate) end: FullOffset, } #[derive(Clone, Debug)] pub(crate) struct AnchorRangeMultimapSummary { - start: usize, - end: usize, - min_start: usize, - max_end: usize, + start: FullOffset, + end: FullOffset, + min_start: FullOffset, + max_end: FullOffset, count: usize, } impl Anchor { pub fn min() -> Self { Self { - full_offset: 0, + full_offset: FullOffset(0), bias: Bias::Left, version: Default::default(), } @@ -68,7 +70,7 @@ impl Anchor { pub fn max() -> Self { Self { - full_offset: usize::MAX, + full_offset: FullOffset::MAX, bias: Bias::Right, version: Default::default(), } @@ -192,7 +194,7 @@ impl AnchorRangeMultimap { { let content = content.clone(); let mut endpoint = Anchor { - full_offset: 0, + full_offset: FullOffset(0), bias: Bias::Right, version: self.version.clone(), }; @@ -219,7 +221,7 @@ impl AnchorRangeMultimap { std::iter::from_fn({ let mut endpoint = Anchor { - full_offset: 0, + full_offset: FullOffset(0), bias: Bias::Left, version: self.version.clone(), }; @@ -260,10 +262,10 @@ impl sum_tree::Item for AnchorRangeMultimapEntry { impl Default for AnchorRangeMultimapSummary { fn default() -> Self { Self { - start: 0, - end: usize::MAX, - min_start: usize::MAX, - max_end: 0, + start: FullOffset(0), + end: FullOffset::MAX, + min_start: FullOffset::MAX, + max_end: FullOffset(0), count: 0, } } @@ -294,8 +296,8 @@ impl sum_tree::Summary for AnchorRangeMultimapSummary { impl Default for FullOffsetRange { fn default() -> Self { Self { - start: 0, - end: usize::MAX, + start: FullOffset(0), + end: FullOffset::MAX, } } } diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 3fc70c437d..00fe10ad33 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -22,7 +22,7 @@ use std::{ cmp::{self, Reverse}, convert::{TryFrom, TryInto}, iter::Iterator, - ops::Range, + ops::{self, Range}, str, sync::Arc, time::{Duration, Instant}, @@ -84,7 +84,7 @@ pub struct Transaction { start: clock::Global, end: clock::Global, edits: Vec, - ranges: Vec>, + ranges: Vec>, selections_before: HashMap>, selections_after: HashMap>, first_edit_at: Instant, @@ -101,7 +101,7 @@ impl Transaction { self.end.observe(edit.timestamp.local()); let mut other_ranges = edit.ranges.iter().peekable(); - let mut new_ranges: Vec> = Vec::new(); + let mut new_ranges = Vec::new(); let insertion_len = edit.new_text.as_ref().map_or(0, |t| t.len()); let mut delta = 0; @@ -429,7 +429,7 @@ pub enum Operation { pub struct EditOperation { timestamp: InsertionTimestamp, version: clock::Global, - ranges: Vec>, + ranges: Vec>, new_text: Option, } @@ -437,7 +437,7 @@ pub struct EditOperation { pub struct UndoOperation { id: clock::Local, counts: HashMap, - ranges: Vec>, + ranges: Vec>, version: clock::Global, } @@ -735,7 +735,7 @@ impl Buffer { fragment_start = old_fragments.start().visible; } - let full_range_start = range.start + old_fragments.start().deleted; + let full_range_start = FullOffset(range.start + old_fragments.start().deleted); // Preserve any portion of the current fragment that precedes this range. if fragment_start < range.start { @@ -783,7 +783,7 @@ impl Buffer { } } - let full_range_end = range.end + old_fragments.start().deleted; + let full_range_end = FullOffset(range.end + old_fragments.start().deleted); edit.ranges.push(full_range_start..full_range_end); } @@ -898,7 +898,7 @@ impl Buffer { fn apply_remote_edit( &mut self, version: &clock::Global, - ranges: &[Range], + ranges: &[Range], new_text: Option<&str>, timestamp: InsertionTimestamp, ) { @@ -909,24 +909,27 @@ impl Buffer { let cx = Some(version.clone()); let mut new_ropes = RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0)); - let mut old_fragments = self.fragments.cursor::(); - let mut new_fragments = - old_fragments.slice(&VersionedOffset::Offset(ranges[0].start), Bias::Left, &cx); + let mut old_fragments = self.fragments.cursor::(); + let mut new_fragments = old_fragments.slice( + &VersionedFullOffset::Offset(ranges[0].start), + Bias::Left, + &cx, + ); new_ropes.push_tree(new_fragments.summary().text); - let mut fragment_start = old_fragments.start().offset(); + let mut fragment_start = old_fragments.start().full_offset(); for range in ranges { - let fragment_end = old_fragments.end(&cx).offset(); + let fragment_end = old_fragments.end(&cx).full_offset(); // If the current fragment ends before this range, then jump ahead to the first fragment // that extends past the start of this range, reusing any intervening fragments. if fragment_end < range.start { // If the current fragment has been partially consumed, then consume the rest of it // and advance to the next fragment before slicing. - if fragment_start > old_fragments.start().offset() { + if fragment_start > old_fragments.start().full_offset() { if fragment_end > fragment_start { let mut suffix = old_fragments.item().unwrap().clone(); - suffix.len = fragment_end - fragment_start; + suffix.len = fragment_end.0 - fragment_start.0; new_ropes.push_fragment(&suffix, suffix.visible); new_fragments.push(suffix, &None); } @@ -934,21 +937,21 @@ impl Buffer { } let slice = - old_fragments.slice(&VersionedOffset::Offset(range.start), Bias::Left, &cx); + old_fragments.slice(&VersionedFullOffset::Offset(range.start), Bias::Left, &cx); new_ropes.push_tree(slice.summary().text); new_fragments.push_tree(slice, &None); - fragment_start = old_fragments.start().offset(); + fragment_start = old_fragments.start().full_offset(); } // If we are at the end of a non-concurrent fragment, advance to the next one. - let fragment_end = old_fragments.end(&cx).offset(); + let fragment_end = old_fragments.end(&cx).full_offset(); if fragment_end == range.start && fragment_end > fragment_start { let mut fragment = old_fragments.item().unwrap().clone(); - fragment.len = fragment_end - fragment_start; + fragment.len = fragment_end.0 - fragment_start.0; new_ropes.push_fragment(&fragment, fragment.visible); new_fragments.push(fragment, &None); old_fragments.next(&cx); - fragment_start = old_fragments.start().offset(); + fragment_start = old_fragments.start().full_offset(); } // Skip over insertions that are concurrent to this edit, but have a lower lamport @@ -970,7 +973,7 @@ impl Buffer { // Preserve any portion of the current fragment that precedes this range. if fragment_start < range.start { let mut prefix = old_fragments.item().unwrap().clone(); - prefix.len = range.start - fragment_start; + prefix.len = range.start.0 - fragment_start.0; fragment_start = range.start; new_ropes.push_fragment(&prefix, prefix.visible); new_fragments.push(prefix, &None); @@ -995,11 +998,11 @@ impl Buffer { // portions as deleted. while fragment_start < range.end { let fragment = old_fragments.item().unwrap(); - let fragment_end = old_fragments.end(&cx).offset(); + let fragment_end = old_fragments.end(&cx).full_offset(); let mut intersection = fragment.clone(); let intersection_end = cmp::min(range.end, fragment_end); if fragment.was_visible(version, &self.undo_map) { - intersection.len = intersection_end - fragment_start; + intersection.len = intersection_end.0 - fragment_start.0; intersection.deletions.insert(timestamp.local()); intersection.visible = false; } @@ -1016,11 +1019,11 @@ impl Buffer { // If the current fragment has been partially consumed, then consume the rest of it // and advance to the next fragment before slicing. - if fragment_start > old_fragments.start().offset() { - let fragment_end = old_fragments.end(&cx).offset(); + if fragment_start > old_fragments.start().full_offset() { + let fragment_end = old_fragments.end(&cx).full_offset(); if fragment_end > fragment_start { let mut suffix = old_fragments.item().unwrap().clone(); - suffix.len = fragment_end - fragment_start; + suffix.len = fragment_end.0 - fragment_start.0; new_ropes.push_fragment(&suffix, suffix.visible); new_fragments.push(suffix, &None); } @@ -1049,9 +1052,9 @@ impl Buffer { } let cx = Some(cx); - let mut old_fragments = self.fragments.cursor::(); + let mut old_fragments = self.fragments.cursor::(); let mut new_fragments = old_fragments.slice( - &VersionedOffset::Offset(undo.ranges[0].start), + &VersionedFullOffset::Offset(undo.ranges[0].start), Bias::Right, &cx, ); @@ -1060,11 +1063,14 @@ impl Buffer { new_ropes.push_tree(new_fragments.summary().text); for range in &undo.ranges { - let mut end_offset = old_fragments.end(&cx).offset(); + let mut end_offset = old_fragments.end(&cx).full_offset(); if end_offset < range.start { - let preceding_fragments = - old_fragments.slice(&VersionedOffset::Offset(range.start), Bias::Right, &cx); + let preceding_fragments = old_fragments.slice( + &VersionedFullOffset::Offset(range.start), + Bias::Right, + &cx, + ); new_ropes.push_tree(preceding_fragments.summary().text); new_fragments.push_tree(preceding_fragments, &None); } @@ -1084,16 +1090,16 @@ impl Buffer { new_fragments.push(fragment, &None); old_fragments.next(&cx); - if end_offset == old_fragments.end(&cx).offset() { + if end_offset == old_fragments.end(&cx).full_offset() { let unseen_fragments = old_fragments.slice( - &VersionedOffset::Offset(end_offset), + &VersionedFullOffset::Offset(end_offset), Bias::Right, &cx, ); new_ropes.push_tree(unseen_fragments.summary().text); new_fragments.push_tree(unseen_fragments, &None); } - end_offset = old_fragments.end(&cx).offset(); + end_offset = old_fragments.end(&cx).full_offset(); } else { break; } @@ -1698,14 +1704,14 @@ impl<'a> Content<'a> { fn summary_for_anchor(&self, anchor: &Anchor) -> TextSummary { let cx = Some(anchor.version.clone()); - let mut cursor = self.fragments.cursor::<(VersionedOffset, usize)>(); + let mut cursor = self.fragments.cursor::<(VersionedFullOffset, usize)>(); cursor.seek( - &VersionedOffset::Offset(anchor.full_offset), + &VersionedFullOffset::Offset(anchor.full_offset), anchor.bias, &cx, ); let overshoot = if cursor.item().map_or(false, |fragment| fragment.visible) { - anchor.full_offset - cursor.start().0.offset() + anchor.full_offset - cursor.start().0.full_offset() } else { 0 }; @@ -1723,11 +1729,11 @@ impl<'a> Content<'a> { let cx = Some(map.version.clone()); let mut summary = TextSummary::default(); let mut rope_cursor = self.visible_text.cursor(0); - let mut cursor = self.fragments.cursor::<(VersionedOffset, usize)>(); + let mut cursor = self.fragments.cursor::<(VersionedFullOffset, usize)>(); map.entries.iter().map(move |((offset, bias), value)| { - cursor.seek_forward(&VersionedOffset::Offset(*offset), *bias, &cx); + cursor.seek_forward(&VersionedFullOffset::Offset(*offset), *bias, &cx); let overshoot = if cursor.item().map_or(false, |fragment| fragment.visible) { - offset - cursor.start().0.offset() + *offset - cursor.start().0.full_offset() } else { 0 }; @@ -1743,25 +1749,29 @@ impl<'a> Content<'a> { let cx = Some(map.version.clone()); let mut summary = TextSummary::default(); let mut rope_cursor = self.visible_text.cursor(0); - let mut cursor = self.fragments.cursor::<(VersionedOffset, usize)>(); + let mut cursor = self.fragments.cursor::<(VersionedFullOffset, usize)>(); map.entries.iter().map(move |(range, value)| { let Range { start: (start_offset, start_bias), end: (end_offset, end_bias), } = range; - cursor.seek_forward(&VersionedOffset::Offset(*start_offset), *start_bias, &cx); + cursor.seek_forward( + &VersionedFullOffset::Offset(*start_offset), + *start_bias, + &cx, + ); let overshoot = if cursor.item().map_or(false, |fragment| fragment.visible) { - start_offset - cursor.start().0.offset() + *start_offset - cursor.start().0.full_offset() } else { 0 }; summary += rope_cursor.summary(cursor.start().1 + overshoot); let start_summary = summary.clone(); - cursor.seek_forward(&VersionedOffset::Offset(*end_offset), *end_bias, &cx); + cursor.seek_forward(&VersionedFullOffset::Offset(*end_offset), *end_bias, &cx); let overshoot = if cursor.item().map_or(false, |fragment| fragment.visible) { - end_offset - cursor.start().0.offset() + *end_offset - cursor.start().0.full_offset() } else { 0 }; @@ -1790,7 +1800,7 @@ impl<'a> Content<'a> { .into_iter() .map(|((offset, bias), value)| { cursor.seek_forward(&offset, bias, &None); - let full_offset = cursor.start().deleted + offset; + let full_offset = FullOffset(cursor.start().deleted + offset); ((full_offset, bias), value) }) .collect(); @@ -1812,9 +1822,9 @@ impl<'a> Content<'a> { end: (end_offset, end_bias), } = range; cursor.seek_forward(&start_offset, start_bias, &None); - let full_start_offset = cursor.start().deleted + start_offset; + let full_start_offset = FullOffset(cursor.start().deleted + start_offset); cursor.seek_forward(&end_offset, end_bias, &None); - let full_end_offset = cursor.start().deleted + end_offset; + let full_end_offset = FullOffset(cursor.start().deleted + end_offset); ( (full_start_offset, start_bias)..(full_end_offset, end_bias), value, @@ -1869,23 +1879,23 @@ impl<'a> Content<'a> { } } - fn full_offset_for_anchor(&self, anchor: &Anchor) -> usize { + fn full_offset_for_anchor(&self, anchor: &Anchor) -> FullOffset { let cx = Some(anchor.version.clone()); let mut cursor = self .fragments - .cursor::<(VersionedOffset, FragmentTextSummary)>(); + .cursor::<(VersionedFullOffset, FragmentTextSummary)>(); cursor.seek( - &VersionedOffset::Offset(anchor.full_offset), + &VersionedFullOffset::Offset(anchor.full_offset), anchor.bias, &cx, ); let overshoot = if cursor.item().is_some() { - anchor.full_offset - cursor.start().0.offset() + anchor.full_offset - cursor.start().0.full_offset() } else { 0 }; let summary = cursor.start().1; - summary.visible + summary.deleted + overshoot + FullOffset(summary.visible + summary.deleted + overshoot) } fn point_for_offset(&self, offset: usize) -> Result { @@ -2118,12 +2128,56 @@ impl Default for FragmentSummary { } } +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FullOffset(usize); + +impl FullOffset { + const MAX: Self = FullOffset(usize::MAX); + + fn to_proto(self) -> u64 { + self.0 as u64 + } + + fn from_proto(value: u64) -> Self { + Self(value as usize) + } +} + +impl ops::AddAssign for FullOffset { + fn add_assign(&mut self, rhs: usize) { + self.0 += rhs; + } +} + +impl ops::Add for FullOffset { + type Output = Self; + + fn add(mut self, rhs: usize) -> Self::Output { + self += rhs; + self + } +} + +impl ops::Sub for FullOffset { + type Output = usize; + + fn sub(self, rhs: Self) -> Self::Output { + self.0 - rhs.0 + } +} + impl<'a> sum_tree::Dimension<'a, FragmentSummary> for usize { fn add_summary(&mut self, summary: &FragmentSummary, _: &Option) { *self += summary.text.visible; } } +impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FullOffset { + fn add_summary(&mut self, summary: &FragmentSummary, _: &Option) { + self.0 += summary.text.visible + summary.text.deleted; + } +} + impl<'a> sum_tree::SeekTarget<'a, FragmentSummary, FragmentTextSummary> for usize { fn cmp( &self, @@ -2135,28 +2189,28 @@ impl<'a> sum_tree::SeekTarget<'a, FragmentSummary, FragmentTextSummary> for usiz } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum VersionedOffset { - Offset(usize), - InvalidVersion, +enum VersionedFullOffset { + Offset(FullOffset), + Invalid, } -impl VersionedOffset { - fn offset(&self) -> usize { - if let Self::Offset(offset) = self { - *offset +impl VersionedFullOffset { + fn full_offset(&self) -> FullOffset { + if let Self::Offset(position) = self { + *position } else { panic!("invalid version") } } } -impl Default for VersionedOffset { +impl Default for VersionedFullOffset { fn default() -> Self { - Self::Offset(0) + Self::Offset(Default::default()) } } -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for VersionedOffset { +impl<'a> sum_tree::Dimension<'a, FragmentSummary> for VersionedFullOffset { fn add_summary(&mut self, summary: &'a FragmentSummary, cx: &Option) { if let Self::Offset(offset) = self { let version = cx.as_ref().unwrap(); @@ -2167,18 +2221,18 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for VersionedOffset { .iter() .all(|t| !version.observed(*t)) { - *self = Self::InvalidVersion; + *self = Self::Invalid; } } } } -impl<'a> sum_tree::SeekTarget<'a, FragmentSummary, Self> for VersionedOffset { - fn cmp(&self, other: &Self, _: &Option) -> cmp::Ordering { - match (self, other) { +impl<'a> sum_tree::SeekTarget<'a, FragmentSummary, Self> for VersionedFullOffset { + fn cmp(&self, cursor_position: &Self, _: &Option) -> cmp::Ordering { + match (self, cursor_position) { (Self::Offset(a), Self::Offset(b)) => Ord::cmp(a, b), - (Self::Offset(_), Self::InvalidVersion) => cmp::Ordering::Less, - (Self::InvalidVersion, _) => unreachable!(), + (Self::Offset(_), Self::Invalid) => cmp::Ordering::Less, + (Self::Invalid, _) => unreachable!(), } } } @@ -2229,8 +2283,8 @@ impl<'a> Into for &'a Operation { .ranges .iter() .map(|r| proto::Range { - start: r.start as u64, - end: r.end as u64, + start: r.start.to_proto(), + end: r.end.to_proto(), }) .collect(), counts: undo @@ -2281,8 +2335,8 @@ impl<'a> Into for &'a EditOperation { .ranges .iter() .map(|range| proto::Range { - start: range.start as u64, - end: range.end as u64, + start: range.start.to_proto(), + end: range.end.to_proto(), }) .collect(); proto::operation::Edit { @@ -2300,7 +2354,7 @@ impl<'a> Into for &'a Anchor { fn into(self) -> proto::Anchor { proto::Anchor { version: (&self.version).into(), - offset: self.full_offset as u64, + offset: self.full_offset.to_proto(), bias: match self.bias { Bias::Left => proto::anchor::Bias::Left as i32, Bias::Right => proto::anchor::Bias::Right as i32, @@ -2356,7 +2410,7 @@ impl TryFrom for Operation { ranges: undo .ranges .into_iter() - .map(|r| r.start as usize..r.end as usize) + .map(|r| FullOffset::from_proto(r.start)..FullOffset::from_proto(r.end)) .collect(), version: undo.version.into(), }, @@ -2406,7 +2460,7 @@ impl From for EditOperation { let ranges = edit .ranges .into_iter() - .map(|range| range.start as usize..range.end as usize) + .map(|range| FullOffset::from_proto(range.start)..FullOffset::from_proto(range.end)) .collect(); EditOperation { timestamp: InsertionTimestamp { @@ -2434,7 +2488,7 @@ impl TryFrom for Anchor { } Ok(Self { - full_offset: message.offset as usize, + full_offset: FullOffset::from_proto(message.offset), bias: if message.bias == proto::anchor::Bias::Left as i32 { Bias::Left } else if message.bias == proto::anchor::Bias::Right as i32 { @@ -2470,12 +2524,12 @@ impl TryFrom for Selection { pub trait ToOffset { fn to_offset<'a>(&self, content: impl Into>) -> usize; - fn to_full_offset<'a>(&self, content: impl Into>, bias: Bias) -> usize { + fn to_full_offset<'a>(&self, content: impl Into>, bias: Bias) -> FullOffset { let content = content.into(); let offset = self.to_offset(&content); let mut cursor = content.fragments.cursor::(); cursor.seek(&offset, bias, &None); - offset + cursor.start().deleted + FullOffset(offset + cursor.start().deleted) } }