use crate::api::*;
use std::mem;
use std::ops::{Range};
struct RopePendingChange {
original_range: Range<usize>,
new_range: Range<usize>,
changed_attributes: bool
}
pub struct PullRope<BaseRope, PullFn>
where
BaseRope: RopeMut,
PullFn: Fn() -> () {
rope: BaseRope,
pull_fn: PullFn,
changes: Vec<RopePendingChange>
}
impl<BaseRope, PullFn> PullRope<BaseRope, PullFn>
where
BaseRope: RopeMut,
PullFn: Fn() -> () {
pub fn from(rope: BaseRope, pull_fn: PullFn) -> PullRope<BaseRope, PullFn> {
PullRope {
rope: rope,
pull_fn: pull_fn,
changes: vec![]
}
}
fn find_change(&self, pos: usize) -> (usize, i64) {
let mut diff = 0;
for idx in 0..self.changes.len() {
let change = &self.changes[idx];
if change.new_range.start <= pos && change.new_range.end > pos {
return (idx, diff);
} else if change.new_range.start > pos {
return (idx, diff);
}
let old_len = change.original_range.len() as i64;
let new_len = change.new_range.len() as i64;
diff += old_len - new_len;
}
(self.changes.len(), diff)
}
#[cfg(test)]
fn check_integrity(&self) {
for change_idx in 1..self.changes.len() {
let last_change = &self.changes[change_idx-1];
let this_change = &self.changes[change_idx];
assert!(last_change.original_range.end <= this_change.original_range.start);
assert!(last_change.new_range.end <= this_change.new_range.start);
}
}
#[cfg(not(test))]
#[inline]
fn check_integrity(&self) {
}
fn mark_change(&mut self, original_range: Range<usize>, new_length: usize, attribute_change: bool) {
let (mut change_idx, mut diff) = self.find_change(original_range.start);
let mut remaining_range = original_range;
let mut remaining_length = new_length;
loop {
self.check_integrity();
if change_idx >= self.changes.len() {
let original_start = (remaining_range.start as i64) + diff;
let original_end = (remaining_range.end as i64) + diff;
let original_start = original_start as usize;
let original_end = original_end as usize;
self.changes.push(RopePendingChange {
original_range: original_start..original_end,
new_range: remaining_range.start..(remaining_range.start+remaining_length),
changed_attributes: attribute_change
});
break;
} else if self.changes[change_idx].new_range.start <= remaining_range.start {
self.changes[change_idx].changed_attributes = self.changes[change_idx].changed_attributes || attribute_change;
let change = &self.changes[change_idx];
if remaining_range.end < change.new_range.end {
let max_diff = change.new_range.len() as i64;
let length_diff = (remaining_range.len() as i64) - (remaining_length as i64);
let length_change = max_diff.min(length_diff);
if length_diff != 0 {
self.changes[change_idx].new_range.end = (self.changes[change_idx].new_range.end as i64 - length_change) as usize;
for move_idx in (change_idx+1)..self.changes.len() {
self.changes[move_idx].new_range.start = (self.changes[move_idx].new_range.start as i64 - length_change) as usize;
self.changes[move_idx].new_range.end = (self.changes[move_idx].new_range.end as i64 - length_change) as usize;
}
}
break;
} else {
let used_length = change.new_range.end - remaining_range.start;
remaining_range.start += used_length;
if remaining_length >= used_length {
remaining_length -= used_length;
} else {
let length_diff = change.new_range.len() - remaining_length;
self.changes[change_idx].new_range.end = self.changes[change_idx].new_range.start + remaining_length;
for move_idx in (change_idx+1)..self.changes.len() {
self.changes[move_idx].new_range.start = self.changes[move_idx].new_range.start - length_diff;
self.changes[move_idx].new_range.end = self.changes[move_idx].new_range.end - length_diff;
}
remaining_range.start -= length_diff;
remaining_range.end -= length_diff;
remaining_length = 0;
if remaining_range.start == remaining_range.end {
break;
}
}
let change = &self.changes[change_idx];
let old_len = change.original_range.len() as i64;
let new_len = change.new_range.len() as i64;
diff += old_len - new_len;
change_idx += 1;
}
} else {
let next_range_start = if change_idx < self.changes.len() {
self.changes[change_idx].new_range.start
} else {
usize::MAX
};
if next_range_start >= remaining_range.end {
let original_start = (remaining_range.start as i64) + diff;
let original_end = (remaining_range.end as i64) + diff;
let original_start = original_start as usize;
let original_end = original_end as usize;
self.changes.insert(change_idx, RopePendingChange {
original_range: original_start..original_end,
new_range: remaining_range.start..(remaining_range.start+remaining_length),
changed_attributes: false
});
let length_diff = (remaining_range.len() as i64) - (remaining_length as i64);
if length_diff != 0 {
for move_idx in (change_idx+1)..self.changes.len() {
self.changes[move_idx].new_range.start = (self.changes[move_idx].new_range.start as i64 - length_diff) as usize;
self.changes[move_idx].new_range.end = (self.changes[move_idx].new_range.end as i64 - length_diff) as usize;
}
}
break;
} else {
let gap_length = next_range_start - remaining_range.start;
let original_start = (remaining_range.start as i64) + diff;
let original_start = original_start as usize;
let gap_end = original_start + gap_length;
if gap_length <= remaining_length {
self.changes.insert(change_idx, RopePendingChange {
original_range: original_start..gap_end,
new_range: remaining_range.start..(remaining_range.start+gap_length),
changed_attributes: attribute_change
});
remaining_range.start += gap_length;
remaining_length -= gap_length;
change_idx += 1;
} else {
self.changes.insert(change_idx, RopePendingChange {
original_range: original_start..gap_end,
new_range: remaining_range.start..(remaining_range.start+remaining_length),
changed_attributes: attribute_change
});
let length_diff = gap_length - remaining_length;
for move_idx in (change_idx+1)..self.changes.len() {
self.changes[move_idx].new_range.start = self.changes[move_idx].new_range.start - length_diff;
self.changes[move_idx].new_range.end = self.changes[move_idx].new_range.end - length_diff;
}
remaining_range.start += remaining_length;
remaining_range.end -= gap_length-remaining_length;
remaining_length = 0;
let change = &self.changes[change_idx];
let old_len = change.original_range.len() as i64;
let new_len = change.new_range.len() as i64;
diff += old_len - new_len;
change_idx += 1;
}
}
}
}
self.check_integrity();
}
pub fn pull_changes<'a>(&'a mut self) -> impl 'a+Iterator<Item=RopeAction<BaseRope::Cell, BaseRope::Attribute>> {
let mut pending_changes = vec![];
mem::swap(&mut self.changes, &mut pending_changes);
pending_changes.into_iter()
.rev()
.filter(|change| change.original_range.len() > 0 || change.new_range.len() > 0)
.flat_map(move |change| {
if change.changed_attributes && change.new_range.len() > 0 {
let mut original_range = change.original_range;
let new_range = change.new_range;
let mut end_pos = new_range.end;
let mut changes = vec![];
loop {
let (attribute, attribute_range) = self.rope.read_attributes(end_pos-1);
let start_pos = new_range.start.max(attribute_range.start);
let valid_range = start_pos..end_pos;
let new_cells = self.read_cells(valid_range).cloned().collect();
changes.push(RopeAction::ReplaceAttributes(original_range.clone(), new_cells, attribute.clone()));
if start_pos <= new_range.start { break; }
original_range = original_range.start..original_range.start;
end_pos = start_pos;
}
changes
} else {
let new_cells = self.rope.read_cells(change.new_range.clone()).cloned().collect::<Vec<_>>();
vec![RopeAction::Replace(change.original_range, new_cells)]
}
})
}
}
impl<BaseRope, PullFn> Rope for PullRope<BaseRope, PullFn>
where
BaseRope: RopeMut,
PullFn: Fn() -> () {
type Cell = BaseRope::Cell;
type Attribute = BaseRope::Attribute;
#[inline]
fn len(&self) -> usize {
self.rope.len()
}
#[inline]
fn read_cells<'a>(&'a self, range: Range<usize>) -> Box<dyn 'a+Iterator<Item=&Self::Cell>> {
self.rope.read_cells(range)
}
#[inline]
fn read_attributes<'a>(&'a self, pos: usize) -> (&'a Self::Attribute, Range<usize>) {
self.rope.read_attributes(pos)
}
}
impl<BaseRope, PullFn> RopeMut for PullRope<BaseRope, PullFn>
where
BaseRope: RopeMut,
PullFn: Fn() -> () {
fn edit(&mut self, action: RopeAction<Self::Cell, Self::Attribute>) {
let need_pull = self.changes.len() == 0;
match &action {
RopeAction::Replace(range, new_values) => self.mark_change(range.clone(), new_values.len(), false),
RopeAction::SetAttributes(range, _attr) => self.mark_change(range.clone(), range.len(), true),
RopeAction::ReplaceAttributes(range, new_values, _attr) => self.mark_change(range.clone(), new_values.len(), true)
}
self.rope.edit(action);
if need_pull && self.changes.len() > 0 {
(self.pull_fn)();
}
}
fn replace<NewCells: IntoIterator<Item=Self::Cell>>(&mut self, range: Range<usize>, new_cells: NewCells) {
let need_pull = self.changes.len() == 0;
let new_cells = new_cells.into_iter().collect::<Vec<_>>();
self.mark_change(range.clone(), new_cells.len(), false);
self.rope.replace(range, new_cells);
if need_pull && self.changes.len() > 0 {
(self.pull_fn)();
}
}
fn set_attributes(&mut self, range: Range<usize>, new_attributes: Self::Attribute) {
let need_pull = self.changes.len() == 0;
self.mark_change(range.clone(), range.len(), true);
self.rope.set_attributes(range, new_attributes);
if need_pull && self.changes.len() > 0 {
(self.pull_fn)();
}
}
fn replace_attributes<NewCells: IntoIterator<Item=Self::Cell>>(&mut self, range: Range<usize>, new_cells: NewCells, new_attributes: Self::Attribute) {
let need_pull = self.changes.len() == 0;
let new_cells = new_cells.into_iter().collect::<Vec<_>>();
self.mark_change(range.clone(), new_cells.len(), true);
self.rope.replace_attributes(range, new_cells, new_attributes);
if need_pull && self.changes.len() > 0 {
(self.pull_fn)();
}
}
}
#[cfg(test)]
mod test {
use crate::*;
use super::*;
#[test]
fn add_initial_change_range() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(4..10, 15, false);
assert!(rope.changes[0].original_range == (4..10));
assert!(rope.changes[0].new_range == (4..19));
assert!(rope.changes.len() == 1);
}
#[test]
fn shrink_range() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..45, 1, false);
assert!(rope.changes[0].original_range == (5..45));
assert!(rope.changes[0].new_range == (5..6));
assert!(rope.changes.len() == 1);
}
#[test]
fn add_multiple_changes_at_end() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(4..10, 15, false);
rope.mark_change(20..25, 5, false);
assert!(rope.changes[1].original_range == (11..16));
assert!(rope.changes[1].new_range == (20..25));
assert!(rope.changes[0].original_range == (4..10));
assert!(rope.changes[0].new_range == (4..19));
assert!(rope.changes.len() == 2);
}
#[test]
fn add_overlapping_range_with_no_size_change() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(4..10, 15, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(6..11, 5, false);
assert!(rope.changes[1].original_range == (11..16));
assert!(rope.changes[1].new_range == (20..25));
assert!(rope.changes[0].original_range == (4..10));
assert!(rope.changes[0].new_range == (4..19));
assert!(rope.changes.len() == 2);
}
#[test]
fn add_overlapping_range_with_size_change() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(4..10, 15, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(6..12, 5, false);
assert!(rope.changes[0].original_range == (4..10));
assert!(rope.changes[0].new_range == (4..18));
assert!(rope.changes[1].original_range == (11..16));
assert!(rope.changes[1].new_range == (19..24));
assert!(rope.changes.len() == 2);
}
#[test]
fn add_overlapping_range_partially_at_end() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(4..10, 15, false);
rope.mark_change(4..30, 20, false);
assert!(rope.changes[0].original_range == (4..10));
assert!(rope.changes[0].new_range == (4..19));
assert!(rope.changes[1].original_range == (10..21));
assert!(rope.changes[1].new_range == (19..24));
assert!(rope.changes.len() == 2);
}
#[test]
fn add_range_covering_existing_ranges() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 15, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(5..30, 40, false);
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (25..45));
assert!(rope.changes[1].original_range == (10..15));
assert!(rope.changes[1].new_range == (20..25));
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..20));
assert!(rope.changes.len() == 3);
}
#[test]
fn add_range_in_gap() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 10, false);
rope.mark_change(15..20, 10, false);
assert!(rope.changes[1].original_range == (10..15));
assert!(rope.changes[1].new_range == (15..25));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (25..35));
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..15));
assert!(rope.changes.len() == 3);
}
#[test]
fn add_range_partially_in_gap() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 10, false);
rope.mark_change(15..18, 8, false);
assert!(rope.changes[1].original_range == (10..13));
assert!(rope.changes[1].new_range == (15..23));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (25..35));
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..15));
assert!(rope.changes.len() == 3);
}
#[test]
fn shrink_gap() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 10, false);
rope.mark_change(15..20, 1, false);
assert!(rope.changes[1].original_range == (10..15));
assert!(rope.changes[1].new_range == (15..16));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (16..26));
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..15));
assert!(rope.changes.len() == 3);
}
#[test]
fn add_range_overlapping_gap() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 10, false);
rope.mark_change(5..20, 20, false);
assert!(rope.changes[1].original_range == (10..15));
assert!(rope.changes[1].new_range == (15..25));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (25..35));
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..15));
assert!(rope.changes.len() == 3);
}
#[test]
fn add_range_partially_overlapping_gap() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 10, false);
rope.mark_change(5..18, 18, false);
assert!(rope.changes[1].original_range == (10..13));
assert!(rope.changes[1].new_range == (15..23));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (25..35));
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..15));
assert!(rope.changes.len() == 3);
}
#[test]
fn add_range_with_gap_between_existing_ranges() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(5..30, 40, false);
assert!(rope.changes[1].original_range == (10..15));
assert!(rope.changes[1].new_range == (15..20));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (20..25));
assert!(rope.changes[3].original_range == (20..25));
assert!(rope.changes[3].new_range == (25..45));
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..15));
assert!(rope.changes.len() == 4);
}
#[test]
fn add_and_shrink_range() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(5..30, 40, false);
rope.mark_change(5..45, 1, false);
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..6));
assert!(rope.changes[1].original_range == (10..15));
assert!(rope.changes[1].new_range == (6..6));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (6..6));
assert!(rope.changes[3].original_range == (20..25));
assert!(rope.changes[3].new_range == (6..6));
assert!(rope.changes.len() == 4);
}
#[test]
fn add_and_shrink_at_end() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(5..45, 1, false);
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..6));
assert!(rope.changes[1].original_range == (10..40));
assert!(rope.changes[1].new_range == (6..6));
assert!(rope.changes.len() == 2);
}
#[test]
fn add_and_shrink_range_across_gap_1() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(5..45, 1, false);
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..6));
assert!(rope.changes[1].original_range == (10..15));
assert!(rope.changes[1].new_range == (6..6));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (6..6));
assert!(rope.changes[3].original_range == (20..40));
assert!(rope.changes[3].new_range == (6..6));
assert!(rope.changes.len() == 4);
}
#[test]
fn add_and_shrink_range_across_gap_2() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 5, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(5..45, 1, false);
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..6));
assert!(rope.changes[1].original_range == (10..20));
assert!(rope.changes[1].new_range == (6..6));
assert!(rope.changes[2].original_range == (20..25));
assert!(rope.changes[2].new_range == (6..6));
assert!(rope.changes[3].original_range == (25..45));
assert!(rope.changes[3].new_range == (6..6));
assert!(rope.changes.len() == 4);
}
#[test]
fn add_and_shrink_range_into_gap() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(5..18, 1, false);
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..6));
assert!(rope.changes[1].original_range == (10..13));
assert!(rope.changes[1].new_range == (6..6));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (8..13));
assert!(rope.changes.len() == 3);
}
#[test]
fn add_and_erase_range() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(5..10, 10, false);
rope.mark_change(20..25, 5, false);
rope.mark_change(5..30, 40, false);
rope.mark_change(5..45, 0, false);
assert!(rope.changes[0].original_range == (5..10));
assert!(rope.changes[0].new_range == (5..5));
assert!(rope.changes[1].original_range == (10..15));
assert!(rope.changes[1].new_range == (5..5));
assert!(rope.changes[2].original_range == (15..20));
assert!(rope.changes[2].new_range == (5..5));
assert!(rope.changes[3].original_range == (20..25));
assert!(rope.changes[3].new_range == (5..5));
assert!(rope.changes.len() == 4);
}
#[test]
fn extend_initial_range() {
let mut rope = PullRope::from(AttributedRope::<u8, ()>::new(), || {});
rope.mark_change(0..0, 3, false);
assert!(rope.changes[0].original_range == (0..0));
assert!(rope.changes[0].new_range == (0..3));
assert!(rope.find_change(0) == (0, 0));
rope.mark_change(1..2, 3, false);
assert!(rope.changes[0].original_range == (0..0));
assert!(rope.changes[0].new_range == (0..5));
assert!(rope.changes.len() == 1);
}
}