#[cfg(feature = "serde")]
pub mod serde;
#[cfg(any(test, bench))]
pub mod utilities;
use bytecount::num_chars;
use std::{cmp::Ordering, error::Error, fmt, iter::FromIterator};
#[derive(Debug, Clone, PartialEq)]
pub enum Operation {
Delete(u64),
Retain(u64),
Insert(String),
}
#[derive(Clone, Debug, PartialEq, Default)]
pub struct OperationSeq {
ops: Vec<Operation>,
base_len: usize,
target_len: usize,
}
impl FromIterator<Operation> for OperationSeq {
fn from_iter<T: IntoIterator<Item = Operation>>(ops: T) -> Self {
let mut operations = OperationSeq::default();
for op in ops {
operations.add(op);
}
operations
}
}
#[derive(Clone, Debug)]
pub struct OTError;
impl fmt::Display for OTError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "incompatible lengths")
}
}
impl Error for OTError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
impl OperationSeq {
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
ops: Vec::with_capacity(capacity),
base_len: 0,
target_len: 0,
}
}
pub fn compose(&self, other: &Self) -> Result<Self, OTError> {
if self.target_len != other.base_len {
return Err(OTError);
}
let mut new_op_seq = OperationSeq::default();
let mut ops1 = self.ops.iter().cloned();
let mut ops2 = other.ops.iter().cloned();
let mut maybe_op1 = ops1.next();
let mut maybe_op2 = ops2.next();
loop {
match (&maybe_op1, &maybe_op2) {
(None, None) => break,
(Some(Operation::Delete(i)), _) => {
new_op_seq.delete(*i);
maybe_op1 = ops1.next();
}
(_, Some(Operation::Insert(s))) => {
new_op_seq.insert(s);
maybe_op2 = ops2.next();
}
(None, _) | (_, None) => {
return Err(OTError);
}
(Some(Operation::Retain(i)), Some(Operation::Retain(j))) => match i.cmp(j) {
Ordering::Less => {
new_op_seq.retain(*i);
maybe_op2 = Some(Operation::Retain(*j - *i));
maybe_op1 = ops1.next();
}
std::cmp::Ordering::Equal => {
new_op_seq.retain(*i);
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
}
std::cmp::Ordering::Greater => {
new_op_seq.retain(*j);
maybe_op1 = Some(Operation::Retain(*i - *j));
maybe_op2 = ops2.next();
}
},
(Some(Operation::Insert(s)), Some(Operation::Delete(j))) => {
match (num_chars(s.as_bytes()) as u64).cmp(j) {
Ordering::Less => {
maybe_op2 =
Some(Operation::Delete(*j - num_chars(s.as_bytes()) as u64));
maybe_op1 = ops1.next();
}
Ordering::Equal => {
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
}
Ordering::Greater => {
maybe_op1 =
Some(Operation::Insert(s.chars().skip(*j as usize).collect()));
maybe_op2 = ops2.next();
}
}
}
(Some(Operation::Insert(s)), Some(Operation::Retain(j))) => {
match (num_chars(s.as_bytes()) as u64).cmp(j) {
Ordering::Less => {
new_op_seq.insert(s);
maybe_op2 =
Some(Operation::Retain(*j - num_chars(s.as_bytes()) as u64));
maybe_op1 = ops1.next();
}
Ordering::Equal => {
new_op_seq.insert(s);
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
}
Ordering::Greater => {
let chars = &mut s.chars();
new_op_seq.insert(&chars.take(*j as usize).collect::<String>());
maybe_op1 = Some(Operation::Insert(chars.collect()));
maybe_op2 = ops2.next();
}
}
}
(Some(Operation::Retain(i)), Some(Operation::Delete(j))) => match i.cmp(j) {
Ordering::Less => {
new_op_seq.delete(*i);
maybe_op2 = Some(Operation::Delete(*j - *i));
maybe_op1 = ops1.next();
}
Ordering::Equal => {
new_op_seq.delete(*j);
maybe_op2 = ops2.next();
maybe_op1 = ops1.next();
}
Ordering::Greater => {
new_op_seq.delete(*j);
maybe_op1 = Some(Operation::Retain(*i - *j));
maybe_op2 = ops2.next();
}
},
};
}
Ok(new_op_seq)
}
fn add(&mut self, op: Operation) {
match op {
Operation::Delete(i) => self.delete(i),
Operation::Insert(s) => self.insert(&s),
Operation::Retain(i) => self.retain(i),
}
}
pub fn delete(&mut self, n: u64) {
if n == 0 {
return;
}
self.base_len += n as usize;
if let Some(Operation::Delete(n_last)) = self.ops.last_mut() {
*n_last += n;
} else {
self.ops.push(Operation::Delete(n));
}
}
pub fn insert(&mut self, s: &str) {
if s.is_empty() {
return;
}
self.target_len += num_chars(s.as_bytes());
let new_last = match self.ops.as_mut_slice() {
[.., Operation::Insert(s_last)] => {
*s_last += s;
return;
}
[.., Operation::Insert(s_pre_last), Operation::Delete(_)] => {
*s_pre_last += s;
return;
}
[.., op_last @ Operation::Delete(_)] => {
let new_last = op_last.clone();
*op_last = Operation::Insert(s.to_owned());
new_last
}
_ => Operation::Insert(s.to_owned()),
};
self.ops.push(new_last);
}
pub fn retain(&mut self, n: u64) {
if n == 0 {
return;
}
self.base_len += n as usize;
self.target_len += n as usize;
if let Some(Operation::Retain(i_last)) = self.ops.last_mut() {
*i_last += n;
} else {
self.ops.push(Operation::Retain(n));
}
}
pub fn transform(&self, other: &Self) -> Result<(Self, Self), OTError> {
if self.base_len != other.base_len {
return Err(OTError);
}
let mut a_prime = OperationSeq::default();
let mut b_prime = OperationSeq::default();
let mut ops1 = self.ops.iter().cloned();
let mut ops2 = other.ops.iter().cloned();
let mut maybe_op1 = ops1.next();
let mut maybe_op2 = ops2.next();
loop {
match (&maybe_op1, &maybe_op2) {
(None, None) => break,
(Some(Operation::Insert(s)), _) => {
a_prime.insert(s);
b_prime.retain(num_chars(s.as_bytes()) as _);
maybe_op1 = ops1.next();
}
(_, Some(Operation::Insert(s))) => {
a_prime.retain(num_chars(s.as_bytes()) as _);
b_prime.insert(s);
maybe_op2 = ops2.next();
}
(None, _) => {
return Err(OTError);
}
(_, None) => {
return Err(OTError);
}
(Some(Operation::Retain(i)), Some(Operation::Retain(j))) => {
match i.cmp(j) {
Ordering::Less => {
a_prime.retain(*i);
b_prime.retain(*i);
maybe_op2 = Some(Operation::Retain(*j - *i));
maybe_op1 = ops1.next();
}
Ordering::Equal => {
a_prime.retain(*i);
b_prime.retain(*i);
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
}
Ordering::Greater => {
a_prime.retain(*j);
b_prime.retain(*j);
maybe_op1 = Some(Operation::Retain(*i - *j));
maybe_op2 = ops2.next();
}
};
}
(Some(Operation::Delete(i)), Some(Operation::Delete(j))) => match i.cmp(j) {
Ordering::Less => {
maybe_op2 = Some(Operation::Delete(*j - *i));
maybe_op1 = ops1.next();
}
Ordering::Equal => {
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
}
Ordering::Greater => {
maybe_op1 = Some(Operation::Delete(*i - *j));
maybe_op2 = ops2.next();
}
},
(Some(Operation::Delete(i)), Some(Operation::Retain(j))) => {
match i.cmp(j) {
Ordering::Less => {
a_prime.delete(*i);
maybe_op2 = Some(Operation::Retain(*j - *i));
maybe_op1 = ops1.next();
}
Ordering::Equal => {
a_prime.delete(*i);
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
}
Ordering::Greater => {
a_prime.delete(*j);
maybe_op1 = Some(Operation::Delete(*i - *j));
maybe_op2 = ops2.next();
}
};
}
(Some(Operation::Retain(i)), Some(Operation::Delete(j))) => {
match i.cmp(j) {
Ordering::Less => {
b_prime.delete(*i);
maybe_op2 = Some(Operation::Delete(*j - *i));
maybe_op1 = ops1.next();
}
Ordering::Equal => {
b_prime.delete(*i);
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
}
Ordering::Greater => {
b_prime.delete(*j);
maybe_op1 = Some(Operation::Retain(*i - *j));
maybe_op2 = ops2.next();
}
};
}
}
}
Ok((a_prime, b_prime))
}
pub fn apply(&self, s: &str) -> Result<String, OTError> {
if num_chars(s.as_bytes()) != self.base_len {
return Err(OTError);
}
let mut new_s = String::new();
let chars = &mut s.chars();
for op in &self.ops {
match op {
Operation::Retain(retain) => {
for c in chars.take(*retain as usize) {
new_s.push(c);
}
}
Operation::Delete(delete) => {
for _ in 0..*delete {
chars.next();
}
}
Operation::Insert(insert) => {
new_s += insert;
}
}
}
Ok(new_s)
}
pub fn invert(&self, s: &str) -> Self {
let mut inverse = OperationSeq::default();
let chars = &mut s.chars();
for op in &self.ops {
match op {
Operation::Retain(retain) => {
inverse.retain(*retain);
for _ in 0..*retain {
chars.next();
}
}
Operation::Insert(insert) => {
inverse.delete(num_chars(insert.as_bytes()) as u64);
}
Operation::Delete(delete) => {
inverse.insert(&chars.take(*delete as usize).collect::<String>());
}
}
}
inverse
}
#[inline]
pub fn is_noop(&self) -> bool {
matches!(self.ops.as_slice(), [] | [Operation::Retain(_)])
}
#[inline]
pub fn base_len(&self) -> usize {
self.base_len
}
#[inline]
pub fn target_len(&self) -> usize {
self.target_len
}
#[inline]
pub fn ops(&self) -> &[Operation] {
&self.ops
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::utilities::Rng;
#[test]
fn lengths() {
let mut o = OperationSeq::default();
assert_eq!(o.base_len, 0);
assert_eq!(o.target_len, 0);
o.retain(5);
assert_eq!(o.base_len, 5);
assert_eq!(o.target_len, 5);
o.insert("abc");
assert_eq!(o.base_len, 5);
assert_eq!(o.target_len, 8);
o.retain(2);
assert_eq!(o.base_len, 7);
assert_eq!(o.target_len, 10);
o.delete(2);
assert_eq!(o.base_len, 9);
assert_eq!(o.target_len, 10);
}
#[test]
fn sequence() {
let mut o = OperationSeq::default();
o.retain(5);
o.retain(0);
o.insert("lorem");
o.insert("");
o.delete(3);
o.delete(0);
assert_eq!(o.ops.len(), 3);
}
#[test]
fn apply() {
for _ in 0..1000 {
let mut rng = Rng::default();
let s = rng.gen_string(50);
let o = rng.gen_operation_seq(&s);
assert_eq!(num_chars(s.as_bytes()), o.base_len);
assert_eq!(o.apply(&s).unwrap().chars().count(), o.target_len);
}
}
#[test]
fn invert() {
for _ in 0..1000 {
let mut rng = Rng::default();
let s = rng.gen_string(50);
let o = rng.gen_operation_seq(&s);
let p = o.invert(&s);
assert_eq!(o.base_len, p.target_len);
assert_eq!(o.target_len, p.base_len);
assert_eq!(p.apply(&o.apply(&s).unwrap()).unwrap(), s);
}
}
#[test]
fn empty_ops() {
let mut o = OperationSeq::default();
o.retain(0);
o.insert("");
o.delete(0);
assert_eq!(o.ops.len(), 0);
}
#[test]
fn eq() {
let mut o1 = OperationSeq::default();
o1.delete(1);
o1.insert("lo");
o1.retain(2);
o1.retain(3);
let mut o2 = OperationSeq::default();
o2.delete(1);
o2.insert("l");
o2.insert("o");
o2.retain(5);
assert_eq!(o1, o2);
o1.delete(1);
o2.retain(1);
assert_ne!(o1, o2);
}
#[test]
fn ops_merging() {
let mut o = OperationSeq::default();
assert_eq!(o.ops.len(), 0);
o.retain(2);
assert_eq!(o.ops.len(), 1);
assert_eq!(o.ops.last(), Some(&Operation::Retain(2)));
o.retain(3);
assert_eq!(o.ops.len(), 1);
assert_eq!(o.ops.last(), Some(&Operation::Retain(5)));
o.insert("abc");
assert_eq!(o.ops.len(), 2);
assert_eq!(o.ops.last(), Some(&Operation::Insert("abc".to_owned())));
o.insert("xyz");
assert_eq!(o.ops.len(), 2);
assert_eq!(o.ops.last(), Some(&Operation::Insert("abcxyz".to_owned())));
o.delete(1);
assert_eq!(o.ops.len(), 3);
assert_eq!(o.ops.last(), Some(&Operation::Delete(1)));
o.delete(1);
assert_eq!(o.ops.len(), 3);
assert_eq!(o.ops.last(), Some(&Operation::Delete(2)));
}
#[test]
fn is_noop() {
let mut o = OperationSeq::default();
assert!(o.is_noop());
o.retain(5);
assert!(o.is_noop());
o.retain(3);
assert!(o.is_noop());
o.insert("lorem");
assert!(!o.is_noop());
}
#[test]
fn compose() {
for _ in 0..1000 {
let mut rng = Rng::default();
let s = rng.gen_string(20);
let a = rng.gen_operation_seq(&s);
let after_a = a.apply(&s).unwrap();
assert_eq!(a.target_len, num_chars(after_a.as_bytes()));
let b = rng.gen_operation_seq(&after_a);
let after_b = b.apply(&after_a).unwrap();
assert_eq!(b.target_len, num_chars(after_b.as_bytes()));
let ab = a.compose(&b).unwrap();
assert_eq!(ab.target_len, b.target_len);
let after_ab = ab.apply(&s).unwrap();
assert_eq!(after_b, after_ab);
}
}
#[test]
fn transform() {
for _ in 0..1000 {
let mut rng = Rng::default();
let s = rng.gen_string(20);
let a = rng.gen_operation_seq(&s);
let b = rng.gen_operation_seq(&s);
let (a_prime, b_prime) = a.transform(&b).unwrap();
let ab_prime = a.compose(&b_prime).unwrap();
let ba_prime = b.compose(&a_prime).unwrap();
let after_ab_prime = ab_prime.apply(&s).unwrap();
let after_ba_prime = ba_prime.apply(&s).unwrap();
assert_eq!(ab_prime, ba_prime);
assert_eq!(after_ab_prime, after_ba_prime);
}
}
#[test]
#[cfg(feature = "serde")]
fn serde() {
use serde_json;
let mut rng = Rng::default();
let o: OperationSeq = serde_json::from_str("[1,-1,\"abc\"]").unwrap();
let mut o_exp = OperationSeq::default();
o_exp.retain(1);
o_exp.delete(1);
o_exp.insert("abc");
assert_eq!(o, o_exp);
for _ in 0..1000 {
let s = rng.gen_string(20);
let o = rng.gen_operation_seq(&s);
assert_eq!(
o,
serde_json::from_str(&serde_json::to_string(&o).unwrap()).unwrap()
);
}
}
}