mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
config delta
This commit is contained in:
parent
a3ed1b2874
commit
eae0c17dda
@ -12,7 +12,7 @@ impl Attributes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_empty_value(&mut self) { self.inner.retain((|_, v| v.is_empty())); }
|
pub fn remove_empty_value(&mut self) { self.inner.retain(|_, v| v.is_empty()); }
|
||||||
|
|
||||||
pub fn extend(&mut self, other: Attributes) { self.inner.extend(other.inner); }
|
pub fn extend(&mut self, other: Attributes) { self.inner.extend(other.inner); }
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ pub fn invert_attributes(attr: Option<Attributes>, base: Option<Attributes>) ->
|
|||||||
attributes
|
attributes
|
||||||
});
|
});
|
||||||
|
|
||||||
let inverted = attr.iter().fold(base_inverted, |mut attributes, (k, v)| {
|
let inverted = attr.iter().fold(base_inverted, |mut attributes, (k, _)| {
|
||||||
if base.get(k) != attr.get(k) && !base.contains_key(k) {
|
if base.get(k) != attr.get(k) && !base.contains_key(k) {
|
||||||
attributes.insert(k.clone(), "".to_owned());
|
attributes.insert(k.clone(), "".to_owned());
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{attributes::*, errors::OTError, operation::*};
|
use crate::{attributes::*, errors::OTError, operation::*};
|
||||||
use bytecount::num_chars;
|
use bytecount::num_chars;
|
||||||
use std::{cmp::Ordering, error::Error, fmt, iter::FromIterator};
|
use std::{cmp::Ordering, error::Error, fmt, iter::FromIterator, str::FromStr};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Delta {
|
pub struct Delta {
|
||||||
@ -19,15 +19,29 @@ impl Default for Delta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl FromIterator<OpType> for Delta {
|
impl FromStr for Delta {
|
||||||
// fn from_iter<T: IntoIterator<Item = OpType>>(ops: T) -> Self {
|
type Err = ();
|
||||||
// let mut operations = Delta::default();
|
|
||||||
// for op in ops {
|
fn from_str(s: &str) -> Result<Delta, Self::Err> {
|
||||||
// operations.add(op);
|
let mut delta = Delta::with_capacity(1);
|
||||||
// }
|
delta.add(Operation::Insert(s.into()));
|
||||||
// operations
|
Ok(delta)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> From<T> for Delta {
|
||||||
|
fn from(s: T) -> Delta { Delta::from_str(s.as_ref()).unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromIterator<Operation> for Delta {
|
||||||
|
fn from_iter<T: IntoIterator<Item = Operation>>(ops: T) -> Self {
|
||||||
|
let mut operations = Delta::default();
|
||||||
|
for op in ops {
|
||||||
|
operations.add(op);
|
||||||
|
}
|
||||||
|
operations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Delta {
|
impl Delta {
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -39,28 +53,24 @@ impl Delta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn add(&mut self, op: OpType) {
|
fn add(&mut self, op: Operation) {
|
||||||
// match op {
|
match op {
|
||||||
// OpType::Delete(i) => self.delete(i),
|
Operation::Delete(i) => self.delete(i),
|
||||||
// OpType::Insert(s) => self.insert(&s),
|
Operation::Insert(i) => self.insert(&i.s, i.attrs),
|
||||||
// OpType::Retain(i) => self.retain(i),
|
Operation::Retain(r) => self.retain(r.n, r.attrs),
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
pub fn delete(&mut self, n: u64) {
|
pub fn delete(&mut self, n: u64) {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.base_len += n as usize;
|
self.base_len += n as usize;
|
||||||
|
if let Some(Operation::Delete(n_last)) = self.ops.last_mut() {
|
||||||
if let Some(operation) = self.ops.last_mut() {
|
*n_last += n;
|
||||||
if operation.ty.is_delete() {
|
} else {
|
||||||
operation.delete(n);
|
self.ops.push(OpBuilder::delete(n).build());
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ops.push(OperationBuilder::delete(n).build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, s: &str, attrs: Option<Attributes>) {
|
pub fn insert(&mut self, s: &str, attrs: Option<Attributes>) {
|
||||||
@ -68,30 +78,25 @@ impl Delta {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.target_len += num_chars(s.as_bytes());
|
self.target_len += num_chars(s.as_bytes());
|
||||||
let new_last = match self
|
|
||||||
.ops
|
let new_last = match self.ops.as_mut_slice() {
|
||||||
.iter_mut()
|
[.., Operation::Insert(s_last)] => {
|
||||||
.map(|op| &mut op.ty)
|
s_last.s += &s;
|
||||||
.collect::<Vec<&mut OpType>>()
|
|
||||||
.as_mut_slice()
|
|
||||||
{
|
|
||||||
[.., OpType::Insert(s_last)] => {
|
|
||||||
*s_last += &s;
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
[.., OpType::Insert(s_pre_last), OpType::Delete(_)] => {
|
[.., Operation::Insert(s_pre_last), Operation::Delete(_)] => {
|
||||||
*s_pre_last += s;
|
s_pre_last.s += s;
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
[.., op_last @ OpType::Delete(_)] => {
|
[.., op_last @ Operation::Delete(_)] => {
|
||||||
let new_last = op_last.clone();
|
let new_last = op_last.clone();
|
||||||
*(*op_last) = OpType::Insert(s.to_owned());
|
*op_last = Operation::Insert(s.into());
|
||||||
new_last
|
new_last
|
||||||
},
|
},
|
||||||
_ => OpType::Insert(s.to_owned()),
|
_ => Operation::Insert(s.into()),
|
||||||
};
|
};
|
||||||
self.ops
|
self.ops
|
||||||
.push(OperationBuilder::new(new_last).with_attrs(attrs).build());
|
.push(OpBuilder::new(new_last).with_attrs(attrs).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retain(&mut self, n: u64, attrs: Option<Attributes>) {
|
pub fn retain(&mut self, n: u64, attrs: Option<Attributes>) {
|
||||||
@ -101,16 +106,13 @@ impl Delta {
|
|||||||
self.base_len += n as usize;
|
self.base_len += n as usize;
|
||||||
self.target_len += n as usize;
|
self.target_len += n as usize;
|
||||||
|
|
||||||
if let Some(operation) = self.ops.last_mut() {
|
if let Some(Operation::Retain(i_last)) = self.ops.last_mut() {
|
||||||
if operation.ty.is_retain() {
|
i_last.n += n;
|
||||||
operation.retain(n);
|
i_last.attrs = attrs;
|
||||||
operation.set_attrs(attrs);
|
} else {
|
||||||
return;
|
self.ops
|
||||||
}
|
.push(OpBuilder::retain(n).with_attrs(attrs).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ops
|
|
||||||
.push(OperationBuilder::retain(n).with_attrs(attrs).build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merges the operation with `other` into one operation while preserving
|
/// Merges the operation with `other` into one operation while preserving
|
||||||
@ -132,115 +134,102 @@ impl Delta {
|
|||||||
let mut ops1 = self.ops.iter().cloned();
|
let mut ops1 = self.ops.iter().cloned();
|
||||||
let mut ops2 = other.ops.iter().cloned();
|
let mut ops2 = other.ops.iter().cloned();
|
||||||
|
|
||||||
let mut maybe_op1 = ops1.next();
|
let mut next_op1 = ops1.next();
|
||||||
let mut maybe_op2 = ops2.next();
|
let mut next_op2 = ops2.next();
|
||||||
loop {
|
loop {
|
||||||
match (
|
match (&next_op1, &next_op2) {
|
||||||
&maybe_op1.as_ref().map(|o| &o.ty),
|
|
||||||
&maybe_op2.as_ref().map(|o| &o.ty),
|
|
||||||
) {
|
|
||||||
(None, None) => break,
|
(None, None) => break,
|
||||||
(Some(OpType::Delete(i)), _) => {
|
(Some(Operation::Delete(i)), _) => {
|
||||||
new_delta.delete(*i);
|
new_delta.delete(*i);
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
(_, Some(OpType::Insert(s))) => {
|
(_, Some(Operation::Insert(insert))) => {
|
||||||
new_delta.insert(s, operation_attrs(&maybe_op2));
|
new_delta.insert(&insert.s, get_attrs(&next_op2));
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
(None, _) | (_, None) => {
|
(None, _) | (_, None) => {
|
||||||
return Err(OTError);
|
return Err(OTError);
|
||||||
},
|
},
|
||||||
(Some(OpType::Retain(i)), Some(OpType::Retain(j))) => {
|
(Some(Operation::Retain(i)), Some(Operation::Retain(j))) => {
|
||||||
let new_attrs = compose_attributes(
|
let new_attrs =
|
||||||
operation_attrs(&maybe_op1),
|
compose_attributes(get_attrs(&next_op1), get_attrs(&next_op2), true);
|
||||||
operation_attrs(&maybe_op2),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
match i.cmp(&j) {
|
match i.cmp(&j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
new_delta.retain(*i, new_attrs);
|
new_delta.retain(i.n, new_attrs);
|
||||||
maybe_op2 = Some(OperationBuilder::retain(*j - *i).build());
|
next_op2 = Some(OpBuilder::retain(j.n - i.n).build());
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
new_delta.retain(*i, new_attrs);
|
new_delta.retain(i.n, new_attrs);
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
std::cmp::Ordering::Greater => {
|
std::cmp::Ordering::Greater => {
|
||||||
new_delta.retain(*j, new_attrs);
|
new_delta.retain(j.n, new_attrs);
|
||||||
maybe_op1 = Some(OperationBuilder::retain(*i - *j).build());
|
next_op1 = Some(OpBuilder::retain(i.n - j.n).build());
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(Some(OpType::Insert(s)), Some(OpType::Delete(j))) => {
|
(Some(Operation::Insert(insert)), Some(Operation::Delete(j))) => {
|
||||||
match (num_chars(s.as_bytes()) as u64).cmp(j) {
|
match (num_chars(insert.as_bytes()) as u64).cmp(j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
maybe_op2 = Some(
|
next_op2 = Some(
|
||||||
OperationBuilder::delete(*j - num_chars(s.as_bytes()) as u64)
|
OpBuilder::delete(*j - num_chars(insert.as_bytes()) as u64).build(),
|
||||||
.build(),
|
|
||||||
);
|
);
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
maybe_op1 = Some(
|
next_op1 = Some(
|
||||||
OperationBuilder::insert(s.chars().skip(*j as usize).collect())
|
OpBuilder::insert(insert.chars().skip(*j as usize).collect())
|
||||||
.build(),
|
.build(),
|
||||||
);
|
);
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(Some(OpType::Insert(s)), Some(OpType::Retain(j))) => {
|
(Some(Operation::Insert(insert)), Some(Operation::Retain(j))) => {
|
||||||
let new_attrs = compose_attributes(
|
let new_attrs =
|
||||||
operation_attrs(&maybe_op1),
|
compose_attributes(get_attrs(&next_op1), get_attrs(&next_op2), false);
|
||||||
operation_attrs(&maybe_op2),
|
match (insert.num_chars()).cmp(j) {
|
||||||
false,
|
|
||||||
);
|
|
||||||
match (num_chars(s.as_bytes()) as u64).cmp(j) {
|
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
new_delta.insert(s, new_attrs);
|
new_delta.insert(&insert.s, new_attrs);
|
||||||
maybe_op2 = Some(
|
next_op2 = Some(OpBuilder::retain(j.n - insert.num_chars()).build());
|
||||||
OperationBuilder::retain(*j - num_chars(s.as_bytes()) as u64)
|
next_op1 = ops1.next();
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
maybe_op1 = ops1.next();
|
|
||||||
},
|
},
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
new_delta.insert(s, new_attrs);
|
new_delta.insert(&insert.s, new_attrs);
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
let chars = &mut s.chars();
|
let chars = &mut insert.chars();
|
||||||
new_delta
|
new_delta
|
||||||
.insert(&chars.take(*j as usize).collect::<String>(), new_attrs);
|
.insert(&chars.take(j.n as usize).collect::<String>(), new_attrs);
|
||||||
maybe_op1 = Some(OperationBuilder::insert(chars.collect()).build());
|
next_op1 = Some(OpBuilder::insert(chars.collect()).build());
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(Some(OpType::Retain(i)), Some(OpType::Delete(j))) => match i.cmp(&j) {
|
(Some(Operation::Retain(i)), Some(Operation::Delete(j))) => match i.cmp(&j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
new_delta.delete(*i);
|
new_delta.delete(i.n);
|
||||||
maybe_op2 = Some(OperationBuilder::delete(*j - *i).build());
|
next_op2 = Some(OpBuilder::delete(*j - i.n).build());
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
new_delta.delete(*j);
|
new_delta.delete(*j);
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
new_delta.delete(*j);
|
new_delta.delete(*j);
|
||||||
maybe_op1 = Some(OperationBuilder::retain(*i - *j).build());
|
next_op1 = Some(OpBuilder::retain(i.n - *j).build());
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -268,33 +257,24 @@ impl Delta {
|
|||||||
let mut ops1 = self.ops.iter().cloned();
|
let mut ops1 = self.ops.iter().cloned();
|
||||||
let mut ops2 = other.ops.iter().cloned();
|
let mut ops2 = other.ops.iter().cloned();
|
||||||
|
|
||||||
let mut maybe_op1 = ops1.next();
|
let mut next_op1 = ops1.next();
|
||||||
let mut maybe_op2 = ops2.next();
|
let mut next_op2 = ops2.next();
|
||||||
loop {
|
loop {
|
||||||
match (
|
match (&next_op1, &next_op2) {
|
||||||
&maybe_op1.as_ref().map(|o| &o.ty),
|
|
||||||
&maybe_op2.as_ref().map(|o| &o.ty),
|
|
||||||
) {
|
|
||||||
(None, None) => break,
|
(None, None) => break,
|
||||||
(Some(OpType::Insert(s)), _) => {
|
(Some(Operation::Insert(insert)), _) => {
|
||||||
let new_attrs = compose_attributes(
|
let new_attrs =
|
||||||
operation_attrs(&maybe_op1),
|
compose_attributes(get_attrs(&next_op1), get_attrs(&next_op2), true);
|
||||||
operation_attrs(&maybe_op2),
|
a_prime.insert(&insert.s, new_attrs.clone());
|
||||||
true,
|
b_prime.retain(insert.num_chars(), new_attrs.clone());
|
||||||
);
|
next_op1 = ops1.next();
|
||||||
a_prime.insert(s, new_attrs.clone());
|
|
||||||
b_prime.retain(num_chars(s.as_bytes()) as _, new_attrs.clone());
|
|
||||||
maybe_op1 = ops1.next();
|
|
||||||
},
|
},
|
||||||
(_, Some(OpType::Insert(s))) => {
|
(_, Some(Operation::Insert(insert))) => {
|
||||||
let new_attrs = compose_attributes(
|
let new_attrs =
|
||||||
operation_attrs(&maybe_op1),
|
compose_attributes(get_attrs(&next_op1), get_attrs(&next_op2), true);
|
||||||
operation_attrs(&maybe_op2),
|
a_prime.retain(insert.num_chars(), new_attrs.clone());
|
||||||
true,
|
b_prime.insert(&insert.s, new_attrs.clone());
|
||||||
);
|
next_op2 = ops2.next();
|
||||||
a_prime.retain(num_chars(s.as_bytes()) as _, new_attrs.clone());
|
|
||||||
b_prime.insert(s, new_attrs.clone());
|
|
||||||
maybe_op2 = ops2.next();
|
|
||||||
},
|
},
|
||||||
(None, _) => {
|
(None, _) => {
|
||||||
return Err(OTError);
|
return Err(OTError);
|
||||||
@ -302,82 +282,79 @@ impl Delta {
|
|||||||
(_, None) => {
|
(_, None) => {
|
||||||
return Err(OTError);
|
return Err(OTError);
|
||||||
},
|
},
|
||||||
(Some(OpType::Retain(i)), Some(OpType::Retain(j))) => {
|
(Some(Operation::Retain(i)), Some(Operation::Retain(j))) => {
|
||||||
let new_attrs = compose_attributes(
|
let new_attrs =
|
||||||
operation_attrs(&maybe_op1),
|
compose_attributes(get_attrs(&next_op1), get_attrs(&next_op2), true);
|
||||||
operation_attrs(&maybe_op2),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
match i.cmp(&j) {
|
match i.cmp(&j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
a_prime.retain(*i, new_attrs.clone());
|
a_prime.retain(i.n, new_attrs.clone());
|
||||||
b_prime.retain(*i, new_attrs.clone());
|
b_prime.retain(i.n, new_attrs.clone());
|
||||||
maybe_op2 = Some(OperationBuilder::retain(*j - *i).build());
|
next_op2 = Some(OpBuilder::retain(j.n - i.n).build());
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
a_prime.retain(*i, new_attrs.clone());
|
a_prime.retain(i.n, new_attrs.clone());
|
||||||
b_prime.retain(*i, new_attrs.clone());
|
b_prime.retain(i.n, new_attrs.clone());
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
a_prime.retain(*j, new_attrs.clone());
|
a_prime.retain(j.n, new_attrs.clone());
|
||||||
b_prime.retain(*j, new_attrs.clone());
|
b_prime.retain(j.n, new_attrs.clone());
|
||||||
maybe_op1 = Some(OperationBuilder::retain(*i - *j).build());
|
next_op1 = Some(OpBuilder::retain(i.n - j.n).build());
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(Some(OpType::Delete(i)), Some(OpType::Delete(j))) => match i.cmp(&j) {
|
(Some(Operation::Delete(i)), Some(Operation::Delete(j))) => match i.cmp(&j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
maybe_op2 = Some(OperationBuilder::delete(*j - *i).build());
|
next_op2 = Some(OpBuilder::delete(*j - *i).build());
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
maybe_op1 = Some(OperationBuilder::delete(*i - *j).build());
|
next_op1 = Some(OpBuilder::delete(*i - *j).build());
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
(Some(OpType::Delete(i)), Some(OpType::Retain(j))) => {
|
(Some(Operation::Delete(i)), Some(Operation::Retain(j))) => {
|
||||||
match i.cmp(&j) {
|
match i.cmp(&j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
a_prime.delete(*i);
|
a_prime.delete(*i);
|
||||||
maybe_op2 = Some(OperationBuilder::retain(*j - *i).build());
|
next_op2 = Some(OpBuilder::retain(j.n - *i).build());
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
a_prime.delete(*i);
|
a_prime.delete(*i);
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
a_prime.delete(*j);
|
a_prime.delete(j.n);
|
||||||
maybe_op1 = Some(OperationBuilder::delete(*i - *j).build());
|
next_op1 = Some(OpBuilder::delete(*i - j.n).build());
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(Some(OpType::Retain(i)), Some(OpType::Delete(j))) => {
|
(Some(Operation::Retain(i)), Some(Operation::Delete(j))) => {
|
||||||
match i.cmp(&j) {
|
match i.cmp(&j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
b_prime.delete(*i);
|
b_prime.delete(i.n);
|
||||||
maybe_op2 = Some(OperationBuilder::delete(*j - *i).build());
|
next_op2 = Some(OpBuilder::delete(*j - i.n).build());
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
},
|
},
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
b_prime.delete(*i);
|
b_prime.delete(i.n);
|
||||||
maybe_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
b_prime.delete(*j);
|
b_prime.delete(*j);
|
||||||
maybe_op1 = Some(OperationBuilder::retain(*i - *j).build());
|
next_op1 = Some(OpBuilder::retain(i.n - *j).build());
|
||||||
maybe_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -400,19 +377,19 @@ impl Delta {
|
|||||||
let mut new_s = String::new();
|
let mut new_s = String::new();
|
||||||
let chars = &mut s.chars();
|
let chars = &mut s.chars();
|
||||||
for op in &self.ops {
|
for op in &self.ops {
|
||||||
match &op.ty {
|
match &op {
|
||||||
OpType::Retain(retain) => {
|
Operation::Retain(retain) => {
|
||||||
for c in chars.take(*retain as usize) {
|
for c in chars.take(retain.n as usize) {
|
||||||
new_s.push(c);
|
new_s.push(c);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OpType::Delete(delete) => {
|
Operation::Delete(delete) => {
|
||||||
for _ in 0..*delete {
|
for _ in 0..*delete {
|
||||||
chars.next();
|
chars.next();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OpType::Insert(insert) => {
|
Operation::Insert(insert) => {
|
||||||
new_s += insert;
|
new_s += &insert.s;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,42 +399,36 @@ impl Delta {
|
|||||||
/// Computes the inverse of an operation. The inverse of an operation is the
|
/// Computes the inverse of an operation. The inverse of an operation is the
|
||||||
/// operation that reverts the effects of the operation
|
/// operation that reverts the effects of the operation
|
||||||
pub fn invert(&self, s: &str) -> Self {
|
pub fn invert(&self, s: &str) -> Self {
|
||||||
let mut inverse = Delta::default();
|
let mut inverted = Delta::default();
|
||||||
let chars = &mut s.chars();
|
let chars = &mut s.chars();
|
||||||
for op in &self.ops {
|
for op in &self.ops {
|
||||||
match &op.ty {
|
match &op {
|
||||||
OpType::Retain(retain) => {
|
Operation::Retain(retain) => {
|
||||||
inverse.retain(*retain, op.attrs.clone());
|
inverted.retain(retain.n, None);
|
||||||
for _ in 0..*retain {
|
for _ in 0..retain.n {
|
||||||
chars.next();
|
chars.next();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OpType::Insert(insert) => {
|
Operation::Insert(insert) => {
|
||||||
inverse.delete(num_chars(insert.as_bytes()) as u64);
|
inverted.delete(insert.num_chars());
|
||||||
},
|
},
|
||||||
OpType::Delete(delete) => {
|
Operation::Delete(delete) => {
|
||||||
inverse.insert(
|
inverted.insert(
|
||||||
&chars.take(*delete as usize).collect::<String>(),
|
&chars.take(*delete as usize).collect::<String>(),
|
||||||
op.attrs.clone(),
|
op.attrs(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inverse
|
inverted
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if this operation has no effect.
|
/// Checks if this operation has no effect.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_noop(&self) -> bool {
|
pub fn is_noop(&self) -> bool {
|
||||||
match self
|
match self.ops.as_slice() {
|
||||||
.ops
|
|
||||||
.iter()
|
|
||||||
.map(|op| &op.ty)
|
|
||||||
.collect::<Vec<&OpType>>()
|
|
||||||
.as_slice()
|
|
||||||
{
|
|
||||||
[] => true,
|
[] => true,
|
||||||
[OpType::Retain(_)] => true,
|
[Operation::Retain(_)] => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -474,11 +445,13 @@ impl Delta {
|
|||||||
/// Returns the wrapped sequence of operations.
|
/// Returns the wrapped sequence of operations.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ops(&self) -> &[Operation] { &self.ops }
|
pub fn ops(&self) -> &[Operation] { &self.ops }
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool { self.ops.is_empty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operation_attrs(operation: &Option<Operation>) -> Option<Attributes> {
|
pub fn get_attrs(operation: &Option<Operation>) -> Option<Attributes> {
|
||||||
match operation {
|
match operation {
|
||||||
None => None,
|
None => None,
|
||||||
Some(operation) => operation.attrs.clone(),
|
Some(operation) => operation.attrs(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,105 +1,118 @@
|
|||||||
use crate::attributes::Attributes;
|
use crate::attributes::Attributes;
|
||||||
|
use bytecount::num_chars;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::{hash_map::RandomState, HashMap},
|
collections::{hash_map::RandomState, HashMap},
|
||||||
ops::Deref,
|
ops::{Deref, DerefMut},
|
||||||
|
str::Chars,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Operation {
|
pub enum Operation {
|
||||||
pub ty: OpType,
|
Delete(u64),
|
||||||
pub attrs: Option<Attributes>,
|
Retain(Retain),
|
||||||
|
Insert(Insert),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operation {
|
impl Operation {
|
||||||
pub fn delete(&mut self, n: u64) { self.ty.delete(n); }
|
pub fn is_delete(&self) -> bool {
|
||||||
|
match self {
|
||||||
pub fn retain(&mut self, n: u64) { self.ty.retain(n); }
|
Operation::Delete(_) => true,
|
||||||
|
_ => false,
|
||||||
pub fn set_attrs(&mut self, attrs: Option<Attributes>) { self.attrs = attrs; }
|
|
||||||
|
|
||||||
pub fn is_plain(&self) -> bool {
|
|
||||||
match self.attrs {
|
|
||||||
None => true,
|
|
||||||
Some(ref attrs) => attrs.is_empty(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_noop(&self) -> bool {
|
pub fn is_noop(&self) -> bool {
|
||||||
match self.ty {
|
match self {
|
||||||
OpType::Retain(_) => true,
|
Operation::Retain(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn attrs(&self) -> Option<Attributes> {
|
||||||
|
match self {
|
||||||
|
Operation::Delete(_) => None,
|
||||||
|
Operation::Retain(retain) => retain.attrs.clone(),
|
||||||
|
Operation::Insert(insert) => insert.attrs.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_plain(&self) -> bool { self.attrs().is_none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
pub struct OpBuilder {
|
||||||
pub enum OpType {
|
ty: Operation,
|
||||||
Delete(u64),
|
|
||||||
Retain(u64),
|
|
||||||
Insert(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OpType {
|
|
||||||
pub fn is_delete(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
OpType::Delete(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_retain(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
OpType::Retain(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_insert(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
OpType::Insert(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete(&mut self, n: u64) {
|
|
||||||
debug_assert_eq!(self.is_delete(), true);
|
|
||||||
if let OpType::Delete(n_last) = self {
|
|
||||||
*n_last += n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retain(&mut self, n: u64) {
|
|
||||||
debug_assert_eq!(self.is_retain(), true);
|
|
||||||
if let OpType::Retain(i_last) = self {
|
|
||||||
*i_last += n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OperationBuilder {
|
|
||||||
ty: OpType,
|
|
||||||
attrs: Option<Attributes>,
|
attrs: Option<Attributes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OperationBuilder {
|
impl OpBuilder {
|
||||||
pub fn new(ty: OpType) -> OperationBuilder { OperationBuilder { ty, attrs: None } }
|
pub fn new(ty: Operation) -> OpBuilder { OpBuilder { ty, attrs: None } }
|
||||||
|
|
||||||
pub fn retain(n: u64) -> OperationBuilder { OperationBuilder::new(OpType::Retain(n)) }
|
pub fn retain(n: u64) -> OpBuilder { OpBuilder::new(Operation::Retain(n.into())) }
|
||||||
|
|
||||||
pub fn delete(n: u64) -> OperationBuilder { OperationBuilder::new(OpType::Delete(n)) }
|
pub fn delete(n: u64) -> OpBuilder { OpBuilder::new(Operation::Delete(n)) }
|
||||||
|
|
||||||
pub fn insert(s: String) -> OperationBuilder { OperationBuilder::new(OpType::Insert(s)) }
|
pub fn insert(s: String) -> OpBuilder { OpBuilder::new(Operation::Insert(s.into())) }
|
||||||
|
|
||||||
pub fn with_attrs(mut self, attrs: Option<Attributes>) -> OperationBuilder {
|
pub fn with_attrs(mut self, attrs: Option<Attributes>) -> OpBuilder {
|
||||||
self.attrs = attrs;
|
self.attrs = attrs;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Operation {
|
pub fn build(self) -> Operation {
|
||||||
Operation {
|
let mut operation = self.ty;
|
||||||
ty: self.ty,
|
match &mut operation {
|
||||||
attrs: self.attrs,
|
Operation::Delete(_) => {},
|
||||||
|
Operation::Retain(retain) => retain.attrs = self.attrs,
|
||||||
|
Operation::Insert(insert) => insert.attrs = self.attrs,
|
||||||
|
}
|
||||||
|
operation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Retain {
|
||||||
|
pub n: u64,
|
||||||
|
pub(crate) attrs: Option<Attributes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<u64> for Retain {
|
||||||
|
fn from(n: u64) -> Self { Retain { n, attrs: None } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Retain {
|
||||||
|
type Target = u64;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target { &self.n }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Retain {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.n }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Insert {
|
||||||
|
pub s: String,
|
||||||
|
pub attrs: Option<Attributes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Insert {
|
||||||
|
pub fn as_bytes(&self) -> &[u8] { self.s.as_bytes() }
|
||||||
|
|
||||||
|
pub fn chars(&self) -> Chars<'_> { self.s.chars() }
|
||||||
|
|
||||||
|
pub fn num_chars(&self) -> u64 { num_chars(self.s.as_bytes()) as _ }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<String> for Insert {
|
||||||
|
fn from(s: String) -> Self { Insert { s, attrs: None } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<&str> for Insert {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
Insert {
|
||||||
|
s: s.to_owned(),
|
||||||
|
attrs: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use bytecount::num_chars;
|
|||||||
use flowy_ot::{
|
use flowy_ot::{
|
||||||
attributes::*,
|
attributes::*,
|
||||||
delta::Delta,
|
delta::Delta,
|
||||||
operation::{OpType, OperationBuilder},
|
operation::{OpBuilder, Operation},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -31,7 +31,7 @@ fn sequence() {
|
|||||||
let mut delta = Delta::default();
|
let mut delta = Delta::default();
|
||||||
delta.retain(5, None);
|
delta.retain(5, None);
|
||||||
delta.retain(0, None);
|
delta.retain(0, None);
|
||||||
delta.insert("lorem", None);
|
delta.insert("appflowy", None);
|
||||||
delta.insert("", None);
|
delta.insert("", None);
|
||||||
delta.delete(3);
|
delta.delete(3);
|
||||||
delta.delete(0);
|
delta.delete(0);
|
||||||
@ -64,6 +64,21 @@ fn apply() {
|
|||||||
assert_eq!("hello world,appflowy", &after_b);
|
assert_eq!("hello world,appflowy", &after_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn base_len_test() {
|
||||||
|
let mut delta_a = Delta::default();
|
||||||
|
delta_a.insert("a", None);
|
||||||
|
delta_a.insert("b", None);
|
||||||
|
delta_a.insert("c", None);
|
||||||
|
|
||||||
|
let s = "hello world,".to_owned();
|
||||||
|
delta_a.delete(s.len() as u64);
|
||||||
|
let after_a = delta_a.apply(&s).unwrap();
|
||||||
|
|
||||||
|
delta_a.insert("d", None);
|
||||||
|
assert_eq!("abc", &after_a);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invert() {
|
fn invert() {
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
@ -107,28 +122,28 @@ fn ops_merging() {
|
|||||||
assert_eq!(delta.ops.len(), 0);
|
assert_eq!(delta.ops.len(), 0);
|
||||||
delta.retain(2, None);
|
delta.retain(2, None);
|
||||||
assert_eq!(delta.ops.len(), 1);
|
assert_eq!(delta.ops.len(), 1);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(2).build()));
|
assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(2).build()));
|
||||||
delta.retain(3, None);
|
delta.retain(3, None);
|
||||||
assert_eq!(delta.ops.len(), 1);
|
assert_eq!(delta.ops.len(), 1);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(5).build()));
|
assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(5).build()));
|
||||||
delta.insert("abc", None);
|
delta.insert("abc", None);
|
||||||
assert_eq!(delta.ops.len(), 2);
|
assert_eq!(delta.ops.len(), 2);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
delta.ops.last(),
|
delta.ops.last(),
|
||||||
Some(&OperationBuilder::insert("abc".to_owned()).build())
|
Some(&OpBuilder::insert("abc".to_owned()).build())
|
||||||
);
|
);
|
||||||
delta.insert("xyz", None);
|
delta.insert("xyz", None);
|
||||||
assert_eq!(delta.ops.len(), 2);
|
assert_eq!(delta.ops.len(), 2);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
delta.ops.last(),
|
delta.ops.last(),
|
||||||
Some(&OperationBuilder::insert("abcxyz".to_owned()).build())
|
Some(&OpBuilder::insert("abcxyz".to_owned()).build())
|
||||||
);
|
);
|
||||||
delta.delete(1);
|
delta.delete(1);
|
||||||
assert_eq!(delta.ops.len(), 3);
|
assert_eq!(delta.ops.len(), 3);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(1).build()));
|
assert_eq!(delta.ops.last(), Some(&OpBuilder::delete(1).build()));
|
||||||
delta.delete(1);
|
delta.delete(1);
|
||||||
assert_eq!(delta.ops.len(), 3);
|
assert_eq!(delta.ops.len(), 3);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(2).build()));
|
assert_eq!(delta.ops.last(), Some(&OpBuilder::delete(2).build()));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn is_noop() {
|
fn is_noop() {
|
||||||
|
Loading…
Reference in New Issue
Block a user