check size when applying operations

This commit is contained in:
Nikita Galaiko 2023-03-03 16:06:00 +01:00
parent 887b676acb
commit f78d5b104f
3 changed files with 77 additions and 34 deletions

View File

@ -1,3 +1,4 @@
use anyhow::Result;
use difference::{Changeset, Difference};
use serde::{Deserialize, Serialize};
@ -11,13 +12,40 @@ pub enum Operation {
}
impl Operation {
pub fn apply(&self, text: &mut Vec<char>) {
pub fn apply(&self, text: &mut Vec<char>) -> Result<()> {
match self {
Operation::Insert((index, chunk)) => {
text.splice(*index as usize..*index as usize, chunk.chars());
if *index as usize > text.len() {
Err(anyhow::anyhow!(
"Index out of bounds, {} > {}",
index,
text.len()
))
} else if *index as usize == text.len() {
text.extend(chunk.chars());
Ok(())
} else {
text.splice(*index as usize..*index as usize, chunk.chars());
Ok(())
}
}
Operation::Delete((index, len)) => {
text.splice(*index as usize..(*index + *len) as usize, "".chars());
if *index as usize > text.len() {
Err(anyhow::anyhow!(
"Index out of bounds, {} > {}",
index,
text.len()
))
} else if *index as usize + *len as usize > text.len() {
Err(anyhow::anyhow!(
"Index + length out of bounds, {} > {}",
index + len,
text.len()
))
} else {
text.splice(*index as usize..(*index + *len) as usize, "".chars());
Ok(())
}
}
}
}

View File

@ -1,6 +1,6 @@
use std::time::SystemTime;
use super::{deltas, operations};
use anyhow::Result;
use std::time::SystemTime;
#[derive(Debug, Clone, Default)]
pub struct TextDocument {
@ -8,20 +8,21 @@ pub struct TextDocument {
deltas: Vec<deltas::Delta>,
}
fn apply_deltas(doc: &mut Vec<char>, deltas: &Vec<deltas::Delta>) {
fn apply_deltas(doc: &mut Vec<char>, deltas: &Vec<deltas::Delta>) -> Result<()> {
for delta in deltas {
for operation in &delta.operations {
operation.apply(doc);
operation.apply(doc)?;
}
}
Ok(())
}
impl TextDocument {
// creates a new text document from a deltas.
pub fn from_deltas(deltas: Vec<deltas::Delta>) -> TextDocument {
pub fn from_deltas(deltas: Vec<deltas::Delta>) -> Result<TextDocument> {
let mut doc = vec![];
apply_deltas(&mut doc, &deltas);
TextDocument { doc, deltas }
apply_deltas(&mut doc, &deltas)?;
Ok(TextDocument { doc, deltas })
}
pub fn get_deltas(&self) -> Vec<deltas::Delta> {
@ -29,18 +30,18 @@ impl TextDocument {
}
// returns a text document where internal state is seeded with value, and deltas are applied.
pub fn new(value: &str, deltas: Vec<deltas::Delta>) -> TextDocument {
pub fn new(value: &str, deltas: Vec<deltas::Delta>) -> Result<TextDocument> {
let mut all_deltas = vec![deltas::Delta {
operations: operations::get_delta_operations("", value),
timestamp_ms: 0,
}];
all_deltas.append(&mut deltas.clone());
let mut doc = vec![];
apply_deltas(&mut doc, &all_deltas);
TextDocument { doc, deltas }
apply_deltas(&mut doc, &all_deltas)?;
Ok(TextDocument { doc, deltas })
}
pub fn update(&mut self, value: &str) -> bool {
pub fn update(&mut self, value: &str) -> Result<bool> {
let diffs = operations::get_delta_operations(&self.to_string(), value);
let event = deltas::Delta {
operations: diffs,
@ -50,11 +51,11 @@ impl TextDocument {
.as_millis(),
};
if event.operations.len() == 0 {
return false;
return Ok(false);
}
apply_deltas(&mut self.doc, &vec![event.clone()]);
apply_deltas(&mut self.doc, &vec![event.clone()])?;
self.deltas.push(event);
return true;
return Ok(true);
}
pub fn to_string(&self) -> String {

View File

@ -3,14 +3,18 @@ use crate::deltas::{operations::Operation, text_document::TextDocument, Delta};
#[test]
fn test_new() {
let document = TextDocument::new("hello world", vec![]);
assert_eq!(document.is_ok(), true);
let document = document.unwrap();
assert_eq!(document.to_string(), "hello world");
assert_eq!(document.get_deltas().len(), 0);
}
#[test]
fn test_update() {
let mut document = TextDocument::new("hello world", vec![]);
document.update("hello world!");
let document = TextDocument::new("hello world", vec![]);
assert_eq!(document.is_ok(), true);
let mut document = document.unwrap();
document.update("hello world!").unwrap();
assert_eq!(document.to_string(), "hello world!");
assert_eq!(document.get_deltas().len(), 1);
assert_eq!(document.get_deltas()[0].operations.len(), 1);
@ -22,8 +26,10 @@ fn test_update() {
#[test]
fn test_empty() {
let mut document = TextDocument::from_deltas(vec![]);
document.update("hello world!");
let document = TextDocument::from_deltas(vec![]);
assert_eq!(document.is_ok(), true);
let mut document = document.unwrap();
document.update("hello world!").unwrap();
assert_eq!(document.to_string(), "hello world!");
assert_eq!(document.get_deltas().len(), 1);
assert_eq!(document.get_deltas()[0].operations.len(), 1);
@ -52,14 +58,18 @@ fn test_from_deltas() {
],
},
]);
assert_eq!(document.is_ok(), true);
let document = document.unwrap();
assert_eq!(document.to_string(), "held!");
}
#[test]
fn test_complex_line() {
let mut document = TextDocument::from_deltas(vec![]);
let document = TextDocument::from_deltas(vec![]);
assert_eq!(document.is_ok(), true);
let mut document = document.unwrap();
document.update("hello");
document.update("hello").unwrap();
assert_eq!(document.to_string(), "hello");
assert_eq!(document.get_deltas().len(), 1);
assert_eq!(document.get_deltas()[0].operations.len(), 1);
@ -68,7 +78,7 @@ fn test_complex_line() {
Operation::Insert((0, "hello".to_string()))
);
document.update("hello world");
document.update("hello world").unwrap();
assert_eq!(document.to_string(), "hello world");
assert_eq!(document.get_deltas().len(), 2);
assert_eq!(document.get_deltas()[1].operations.len(), 1);
@ -77,7 +87,7 @@ fn test_complex_line() {
Operation::Insert((5, " world".to_string()))
);
document.update("held!");
document.update("held!").unwrap();
assert_eq!(document.to_string(), "held!");
assert_eq!(document.get_deltas().len(), 3);
assert_eq!(document.get_deltas()[2].operations.len(), 2);
@ -93,9 +103,11 @@ fn test_complex_line() {
#[test]
fn test_multiline_add() {
let mut document = TextDocument::from_deltas(vec![]);
let document = TextDocument::from_deltas(vec![]);
assert_eq!(document.is_ok(), true);
let mut document = document.unwrap();
document.update("first");
document.update("first").unwrap();
assert_eq!(document.to_string(), "first");
assert_eq!(document.get_deltas().len(), 1);
assert_eq!(document.get_deltas()[0].operations.len(), 1);
@ -104,7 +116,7 @@ fn test_multiline_add() {
Operation::Insert((0, "first".to_string()))
);
document.update("first\ntwo");
document.update("first\ntwo").unwrap();
assert_eq!(document.to_string(), "first\ntwo");
assert_eq!(document.get_deltas().len(), 2);
assert_eq!(document.get_deltas()[1].operations.len(), 1);
@ -113,7 +125,7 @@ fn test_multiline_add() {
Operation::Insert((5, "\ntwo".to_string()))
);
document.update("first line\nline two");
document.update("first line\nline two").unwrap();
assert_eq!(document.to_string(), "first line\nline two");
assert_eq!(document.get_deltas().len(), 3);
assert_eq!(document.get_deltas()[2].operations.len(), 2);
@ -129,9 +141,11 @@ fn test_multiline_add() {
#[test]
fn test_multiline_remove() {
let mut document = TextDocument::from_deltas(vec![]);
let document = TextDocument::from_deltas(vec![]);
assert_eq!(document.is_ok(), true);
let mut document = document.unwrap();
document.update("first line\nline two");
document.update("first line\nline two").unwrap();
assert_eq!(document.to_string(), "first line\nline two");
assert_eq!(document.get_deltas().len(), 1);
assert_eq!(document.get_deltas()[0].operations.len(), 1);
@ -140,7 +154,7 @@ fn test_multiline_remove() {
Operation::Insert((0, "first line\nline two".to_string()))
);
document.update("first\ntwo");
document.update("first\ntwo").unwrap();
assert_eq!(document.to_string(), "first\ntwo");
assert_eq!(document.get_deltas().len(), 2);
assert_eq!(document.get_deltas()[1].operations.len(), 2);
@ -153,7 +167,7 @@ fn test_multiline_remove() {
Operation::Delete((6, 5))
);
document.update("first");
document.update("first").unwrap();
assert_eq!(document.to_string(), "first");
assert_eq!(document.get_deltas().len(), 3);
assert_eq!(document.get_deltas()[2].operations.len(), 1);
@ -162,7 +176,7 @@ fn test_multiline_remove() {
Operation::Delete((5, 4))
);
document.update("");
document.update("").unwrap();
assert_eq!(document.to_string(), "");
assert_eq!(document.get_deltas().len(), 4);
assert_eq!(document.get_deltas()[3].operations.len(), 1);