use std::cmp::min;
use std::fmt::Debug;
use std::mem::take;
use super::op::split;
use super::ops::{Delete, Insert, Retain};
use super::{Delta, Len, Op, Seq};
pub trait Transform<Rhs> {
type Output;
fn transform(self, rhs: Rhs, priority: bool) -> Self::Output;
}
impl<T, A> Transform<&mut Insert<T, A>> for &mut Insert<T, A>
where
T: Clone + Default + Extend<T> + Seq,
A: Clone + Default + PartialEq,
{
type Output = Op<T, A>;
fn transform(self, rhs: &mut Insert<T, A>, priority: bool) -> Self::Output {
match priority {
true => take(self).as_retain().into(),
false => take(rhs).into(),
}
}
}
impl<T, A> Transform<&mut Retain<A>> for &mut Insert<T, A>
where
T: Clone + Default + Extend<T> + Seq,
A: Clone + Default + PartialEq,
{
type Output = Retain<A>;
fn transform(self, _rhs: &mut Retain<A>, _priority: bool) -> Self::Output {
take(self).as_retain().into()
}
}
impl<T, A> Transform<&mut Delete> for &mut Insert<T, A>
where
T: Default + Len,
A: Default,
{
type Output = Retain<A>;
fn transform(self, _rhs: &mut Delete, _priority: bool) -> Self::Output {
take(self).as_retain()
}
}
impl<T, A> Transform<&mut Insert<T, A>> for &mut Retain<A>
where
T: Clone + Default + Seq + Extend<T>,
A: Clone + Default + PartialEq,
{
type Output = Insert<T, A>;
fn transform(self, rhs: &mut Insert<T, A>, _priority: bool) -> Self::Output {
take(rhs)
}
}
impl<A> Transform<&mut Retain<A>> for &mut Retain<A>
where
A: Clone + Default,
{
type Output = Retain<A>;
fn transform(self, rhs: &mut Retain<A>, priority: bool) -> Self::Output {
let (lhs, rhs) = split(self, rhs);
match priority {
true => lhs.or(rhs),
false => rhs.or(lhs),
}
}
}
impl<A> Transform<&mut Delete> for &mut Retain<A>
where
A: Clone + Default,
{
type Output = Delete;
fn transform(self, rhs: &mut Delete, _priority: bool) -> Self::Output {
let (_lhs, rhs) = split(self, rhs);
rhs
}
}
impl<T, A> Transform<&mut Insert<T, A>> for &mut Delete
where
T: Default,
A: Default,
{
type Output = Insert<T, A>;
fn transform(self, rhs: &mut Insert<T, A>, _priority: bool) -> Self::Output {
take(rhs)
}
}
impl<A> Transform<&mut Retain<A>> for &mut Delete
where
A: Clone + Default,
{
type Output = Delete;
fn transform(self, rhs: &mut Retain<A>, _priority: bool) -> Self::Output {
let (_, _) = split(self, rhs);
Default::default()
}
}
impl Transform<&mut Delete> for &mut Delete {
type Output = Delete;
fn transform(self, rhs: &mut Delete, _priority: bool) -> Self::Output {
let (_, _) = split(self, rhs);
Default::default()
}
}
impl<T, A> Transform<&mut Op<T, A>> for &mut Op<T, A>
where
T: Clone + Default + Seq + Extend<T>,
A: Clone + Default + PartialEq,
{
type Output = Op<T, A>;
fn transform(self, rhs: &mut Op<T, A>, priority: bool) -> Self::Output {
match self {
Op::Insert(lhs) => match rhs {
Op::Insert(rhs) => lhs.transform(rhs, priority).into(),
Op::Retain(rhs) => lhs.transform(rhs, priority).into(),
Op::Delete(rhs) => lhs.transform(rhs, priority).into(),
},
Op::Retain(lhs) => match rhs {
Op::Insert(rhs) => lhs.transform(rhs, priority).into(),
Op::Retain(rhs) => lhs.transform(rhs, priority).into(),
Op::Delete(rhs) => lhs.transform(rhs, priority).into(),
},
Op::Delete(lhs) => match rhs {
Op::Insert(rhs) => lhs.transform(rhs, priority).into(),
Op::Retain(rhs) => lhs.transform(rhs, priority).into(),
Op::Delete(rhs) => lhs.transform(rhs, priority).into(),
},
}
}
}
impl<T, A> Transform<Delta<T, A>> for Delta<T, A>
where
T: Clone + Default + Seq + Extend<T> + Debug,
A: Clone + Default + PartialEq + Debug,
{
type Output = Delta<T, A>;
fn transform(self, rhs: Delta<T, A>, priority: bool) -> Self::Output {
let mut self_iter = self.into_iter();
let mut other_iter = rhs.into_iter();
let mut result = Delta::new();
result.extend(self_iter.zip_mut(&mut other_iter, |a, b| a.transform(b, priority)));
result.extend(other_iter);
result.chop()
}
}
impl<T, A> Transform<usize> for &Delta<T, A>
where
T: Clone + Default + Seq + Extend<T>,
A: Clone + Default + PartialEq,
{
type Output = usize;
fn transform(self, rhs: usize, priority: bool) -> Self::Output {
let mut index = rhs;
let mut offset = 0;
let mut iter = self.ops();
while let Some(op) = iter.next() {
if offset > rhs {
break;
}
match op {
Op::Insert(insert) => {
if offset < index || !priority {
index += insert.len()
}
offset += insert.len()
}
Op::Retain(retain) => {
offset += retain.len();
}
Op::Delete(delete) => {
index -= min(delete.len(), index - offset);
}
}
}
index
}
}
#[cfg(test)]
mod test {
use super::{Delta, Transform};
#[test]
fn test_insert_before_position() {
let delta = Delta::new().insert("A".to_owned(), ());
assert_eq!((&delta).transform(2, true), 3);
assert_eq!((&delta).transform(2, false), 3);
}
#[test]
fn test_insert_after_position() {
let delta = Delta::new().retain(2, ()).insert("A".to_owned(), ());
assert_eq!((&delta).transform(1, true), 1);
assert_eq!((&delta).transform(1, false), 1);
}
#[test]
fn test_insert_at_position() {
let delta = Delta::new().retain(2, ()).insert("A".to_owned(), ());
assert_eq!((&delta).transform(2, true), 2);
assert_eq!((&delta).transform(2, false), 3);
}
}