@@ -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<T> {
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<T> {
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<T> {
#[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<T: Clone> AnchorRangeMultimap<T> {
{
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<T: Clone> AnchorRangeMultimap<T> {
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<T: Clone> sum_tree::Item for AnchorRangeMultimapEntry<T> {
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,
}
}
}
@@ -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<clock::Local>,
- ranges: Vec<Range<usize>>,
+ ranges: Vec<Range<FullOffset>>,
selections_before: HashMap<SelectionSetId, Arc<[Selection]>>,
selections_after: HashMap<SelectionSetId, Arc<[Selection]>>,
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<Range<usize>> = 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<Range<usize>>,
+ ranges: Vec<Range<FullOffset>>,
new_text: Option<String>,
}
@@ -437,7 +437,7 @@ pub struct EditOperation {
pub struct UndoOperation {
id: clock::Local,
counts: HashMap<clock::Local, u32>,
- ranges: Vec<Range<usize>>,
+ ranges: Vec<Range<FullOffset>>,
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<usize>],
+ ranges: &[Range<FullOffset>],
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::<VersionedOffset>();
- let mut new_fragments =
- old_fragments.slice(&VersionedOffset::Offset(ranges[0].start), Bias::Left, &cx);
+ let mut old_fragments = self.fragments.cursor::<VersionedFullOffset>();
+ 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::<VersionedOffset>();
+ let mut old_fragments = self.fragments.cursor::<VersionedFullOffset>();
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<Point> {
@@ -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<usize> for FullOffset {
+ fn add_assign(&mut self, rhs: usize) {
+ self.0 += rhs;
+ }
+}
+
+impl ops::Add<usize> 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<clock::Global>) {
*self += summary.text.visible;
}
}
+impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FullOffset {
+ fn add_summary(&mut self, summary: &FragmentSummary, _: &Option<clock::Global>) {
+ 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<clock::Global>) {
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<clock::Global>) -> cmp::Ordering {
- match (self, other) {
+impl<'a> sum_tree::SeekTarget<'a, FragmentSummary, Self> for VersionedFullOffset {
+ fn cmp(&self, cursor_position: &Self, _: &Option<clock::Global>) -> 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<proto::Operation> 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<proto::operation::Edit> 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<proto::Anchor> 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<proto::Operation> 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<proto::operation::Edit> 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<proto::Anchor> 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<proto::Selection> for Selection {
pub trait ToOffset {
fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize;
- fn to_full_offset<'a>(&self, content: impl Into<Content<'a>>, bias: Bias) -> usize {
+ fn to_full_offset<'a>(&self, content: impl Into<Content<'a>>, bias: Bias) -> FullOffset {
let content = content.into();
let offset = self.to_offset(&content);
let mut cursor = content.fragments.cursor::<FragmentTextSummary>();
cursor.seek(&offset, bias, &None);
- offset + cursor.start().deleted
+ FullOffset(offset + cursor.start().deleted)
}
}