444 lines
16 KiB
Rust
Raw Normal View History

2021-07-31 20:53:45 +08:00
use crate::{errors::OTError, operation::*};
use bytecount::num_chars;
use std::{cmp::Ordering, error::Error, fmt, iter::FromIterator};
#[derive(Clone, Debug, PartialEq)]
pub struct Delta {
pub ops: Vec<Operation>,
pub base_len: usize,
pub target_len: usize,
}
impl Default for Delta {
fn default() -> Self {
Self {
ops: Vec::new(),
base_len: 0,
target_len: 0,
}
}
}
impl FromIterator<OpType> for Delta {
fn from_iter<T: IntoIterator<Item = OpType>>(ops: T) -> Self {
let mut operations = Delta::default();
for op in ops {
operations.add(op);
}
operations
}
}
impl Delta {
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
ops: Vec::with_capacity(capacity),
base_len: 0,
target_len: 0,
}
}
fn add(&mut self, op: OpType) {
match op {
OpType::Delete(i) => self.delete(i),
OpType::Insert(s) => self.insert(&s),
OpType::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) = self.ops.last_mut() {
if operation.ty.is_delete() {
operation.delete(n);
return;
}
}
self.ops.push(OperationBuilder::delete(n).build());
}
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
.iter_mut()
.map(|op| &mut op.ty)
.collect::<Vec<&mut OpType>>()
.as_mut_slice()
{
[.., OpType::Insert(s_last)] => {
*s_last += &s;
return;
},
[.., OpType::Insert(s_pre_last), OpType::Delete(_)] => {
*s_pre_last += s;
return;
},
[.., op_last @ OpType::Delete(_)] => {
let new_last = op_last.clone();
*(*op_last) = OpType::Insert(s.to_owned());
new_last
},
_ => OpType::Insert(s.to_owned()),
};
self.ops.push(OperationBuilder::new(new_last).build());
}
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) = self.ops.last_mut() {
if operation.ty.is_retain() {
operation.retain(n);
return;
}
}
self.ops.push(OperationBuilder::retain(n).build());
}
/// Merges the operation with `other` into one operation while preserving
/// the changes of both. Or, in other words, for each input string S and a
/// pair of consecutive operations A and B.
/// `apply(apply(S, A), B) = apply(S, compose(A, B))`
/// must hold.
///
/// # Error
///
/// Returns an `OTError` if the operations are not composable due to length
/// conflicts.
pub fn compose(&self, other: &Self) -> Result<Self, OTError> {
if self.target_len != other.base_len {
return Err(OTError);
}
let mut new_delta = Delta::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.as_ref().map(|o| &o.ty),
&maybe_op2.as_ref().map(|o| &o.ty),
) {
(None, None) => break,
(Some(OpType::Delete(i)), _) => {
new_delta.delete(*i);
maybe_op1 = ops1.next();
},
(_, Some(OpType::Insert(s))) => {
new_delta.insert(s);
maybe_op2 = ops2.next();
},
(None, _) | (_, None) => {
return Err(OTError);
},
(Some(OpType::Retain(i)), Some(OpType::Retain(j))) => match i.cmp(&j) {
Ordering::Less => {
new_delta.retain(*i);
maybe_op2 = Some(OperationBuilder::retain(*j - *i).build());
maybe_op1 = ops1.next();
},
std::cmp::Ordering::Equal => {
new_delta.retain(*i);
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
},
std::cmp::Ordering::Greater => {
new_delta.retain(*j);
maybe_op1 = Some(OperationBuilder::retain(*i - *j).build());
maybe_op2 = ops2.next();
},
},
(Some(OpType::Insert(s)), Some(OpType::Delete(j))) => {
match (num_chars(s.as_bytes()) as u64).cmp(j) {
Ordering::Less => {
maybe_op2 = Some(
OperationBuilder::delete(*j - num_chars(s.as_bytes()) as u64)
.build(),
);
maybe_op1 = ops1.next();
},
Ordering::Equal => {
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
},
Ordering::Greater => {
maybe_op1 = Some(
OperationBuilder::insert(s.chars().skip(*j as usize).collect())
.build(),
);
maybe_op2 = ops2.next();
},
}
},
(Some(OpType::Insert(s)), Some(OpType::Retain(j))) => {
match (num_chars(s.as_bytes()) as u64).cmp(j) {
Ordering::Less => {
new_delta.insert(s);
maybe_op2 = Some(
OperationBuilder::retain(*j - num_chars(s.as_bytes()) as u64)
.build(),
);
maybe_op1 = ops1.next();
},
Ordering::Equal => {
new_delta.insert(s);
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
},
Ordering::Greater => {
let chars = &mut s.chars();
new_delta.insert(&chars.take(*j as usize).collect::<String>());
maybe_op1 = Some(OperationBuilder::insert(chars.collect()).build());
maybe_op2 = ops2.next();
},
}
},
(Some(OpType::Retain(i)), Some(OpType::Delete(j))) => match i.cmp(&j) {
Ordering::Less => {
new_delta.delete(*i);
maybe_op2 = Some(OperationBuilder::delete(*j - *i).build());
maybe_op1 = ops1.next();
},
Ordering::Equal => {
new_delta.delete(*j);
maybe_op2 = ops2.next();
maybe_op1 = ops1.next();
},
Ordering::Greater => {
new_delta.delete(*j);
maybe_op1 = Some(OperationBuilder::retain(*i - *j).build());
maybe_op2 = ops2.next();
},
},
};
}
Ok(new_delta)
}
/// Transforms two operations A and B that happened concurrently and
/// produces two operations A' and B' (in an array) such that
/// `apply(apply(S, A), B') = apply(apply(S, B), A')`.
/// This function is the heart of OT.
///
/// # Error
///
/// Returns an `OTError` if the operations cannot be transformed due to
/// length conflicts.
pub fn transform(&self, other: &Self) -> Result<(Self, Self), OTError> {
if self.base_len != other.base_len {
return Err(OTError);
}
let mut a_prime = Delta::default();
let mut b_prime = Delta::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.as_ref().map(|o| &o.ty),
&maybe_op2.as_ref().map(|o| &o.ty),
) {
(None, None) => break,
(Some(OpType::Insert(s)), _) => {
a_prime.insert(s);
b_prime.retain(num_chars(s.as_bytes()) as _);
maybe_op1 = ops1.next();
},
(_, Some(OpType::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(OpType::Retain(i)), Some(OpType::Retain(j))) => {
match i.cmp(&j) {
Ordering::Less => {
a_prime.retain(*i);
b_prime.retain(*i);
maybe_op2 = Some(OperationBuilder::retain(*j - *i).build());
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(OperationBuilder::retain(*i - *j).build());
maybe_op2 = ops2.next();
},
};
},
(Some(OpType::Delete(i)), Some(OpType::Delete(j))) => match i.cmp(&j) {
Ordering::Less => {
maybe_op2 = Some(OperationBuilder::delete(*j - *i).build());
maybe_op1 = ops1.next();
},
Ordering::Equal => {
maybe_op1 = ops1.next();
maybe_op2 = ops2.next();
},
Ordering::Greater => {
maybe_op1 = Some(OperationBuilder::delete(*i - *j).build());
maybe_op2 = ops2.next();
},
},
(Some(OpType::Delete(i)), Some(OpType::Retain(j))) => {
match i.cmp(&j) {
Ordering::Less => {
a_prime.delete(*i);
maybe_op2 = Some(OperationBuilder::retain(*j - *i).build());
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(OperationBuilder::delete(*i - *j).build());
maybe_op2 = ops2.next();
},
};
},
(Some(OpType::Retain(i)), Some(OpType::Delete(j))) => {
match i.cmp(&j) {
Ordering::Less => {
b_prime.delete(*i);
maybe_op2 = Some(OperationBuilder::delete(*j - *i).build());
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(OperationBuilder::retain(*i - *j).build());
maybe_op2 = ops2.next();
},
};
},
}
}
Ok((a_prime, b_prime))
}
/// Applies an operation to a string, returning a new string.
///
/// # Error
///
/// Returns an error if the operation cannot be applied due to length
/// conflicts.
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.ty {
OpType::Retain(retain) => {
for c in chars.take(*retain as usize) {
new_s.push(c);
}
},
OpType::Delete(delete) => {
for _ in 0..*delete {
chars.next();
}
},
OpType::Insert(insert) => {
new_s += insert;
},
}
}
Ok(new_s)
}
/// Computes the inverse of an operation. The inverse of an operation is the
/// operation that reverts the effects of the operation
pub fn invert(&self, s: &str) -> Self {
let mut inverse = Delta::default();
let chars = &mut s.chars();
for op in &self.ops {
match &op.ty {
OpType::Retain(retain) => {
inverse.retain(*retain);
for _ in 0..*retain {
chars.next();
}
},
OpType::Insert(insert) => {
inverse.delete(num_chars(insert.as_bytes()) as u64);
},
OpType::Delete(delete) => {
inverse.insert(&chars.take(*delete as usize).collect::<String>());
},
}
}
inverse
}
/// Checks if this operation has no effect.
#[inline]
pub fn is_noop(&self) -> bool {
match self
.ops
.iter()
.map(|op| &op.ty)
.collect::<Vec<&OpType>>()
.as_slice()
{
[] => true,
[OpType::Retain(_)] => true,
_ => false,
}
}
/// Returns the length of a string these operations can be applied to
#[inline]
pub fn base_len(&self) -> usize { self.base_len }
/// Returns the length of the resulting string after the operations have
/// been applied.
#[inline]
pub fn target_len(&self) -> usize { self.target_len }
/// Returns the wrapped sequence of operations.
#[inline]
pub fn ops(&self) -> &[Operation] { &self.ops }
}