use crate::{Apply, Core, Delta, DeltaError, DeltaResult, FromDelta, IntoDelta};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
impl<T> Core for Vec<T>
where T: Clone + Debug + PartialEq + Core
+ for<'de> Deserialize<'de>
+ Serialize
{
type Delta = VecDelta<T>;
}
impl<T> Apply for Vec<T>
where T: Clone + Debug + PartialEq + Apply + FromDelta
+ for<'de> Deserialize<'de>
+ Serialize
{
fn apply(&self, delta: Self::Delta) -> DeltaResult<Self> {
let mut new: Self = self.clone();
for change in delta.into_iter() { match change {
EltDelta::Edit { index, item } => {
ensure_gt![self.len(), 0]?;
ensure_lt![index, self.len()]?;
new[index] = self[index].apply(item)?;
},
EltDelta::Add(delta) => new.push(<T>::from_delta(delta)?),
EltDelta::Remove { count } => for _ in 0 .. count {
new.pop().ok_or_else(|| ExpectedValue!("VecDelta<T>"))?;
},
}}
Ok(new)
}
}
impl<T> Delta for Vec<T>
where T: Clone + Debug + PartialEq + Delta + IntoDelta
+ for<'de> Deserialize<'de>
+ Serialize
{
fn delta(&self, rhs: &Self) -> DeltaResult<Self::Delta> {
let (lhs_len, rhs_len) = (self.len(), rhs.len());
let max_len = usize::max(lhs_len, rhs_len);
let mut changes: Vec<EltDelta<T>> = vec![];
for index in 0 .. max_len { match (self.get(index), rhs.get(index)) {
(None, None) => return bug_detected!(),
(Some(lhs), Some(rhs)) if lhs == rhs => {},
(Some(lhs), Some(rhs)) =>
changes.push(EltDelta::Edit { index, item: lhs.delta(rhs)? }),
(None, Some(rhs)) =>
changes.push(EltDelta::Add(rhs.clone().into_delta()?)),
(Some(_), None) => match changes.last_mut() {
Some(EltDelta::Remove { ref mut count }) => *count += 1,
_ => changes.push(EltDelta::Remove { count: 1 }),
},
}}
Ok(VecDelta(changes))
}
}
impl<T> FromDelta for Vec<T>
where T: Clone + Debug + PartialEq + FromDelta
+ for<'de> Deserialize<'de>
+ Serialize
{
fn from_delta(delta: <Self as Core>::Delta) -> DeltaResult<Self> {
let mut vec: Vec<T> = vec![];
for (index, element) in delta.0.into_iter().enumerate() {
match element {
EltDelta::Add(elt) => vec.push(<T>::from_delta(elt)?),
_ => return Err(DeltaError::IllegalDelta { index })?,
}
}
Ok(vec)
}
}
impl<T> IntoDelta for Vec<T>
where T: Clone + Debug + PartialEq + IntoDelta
+ for<'de> Deserialize<'de>
+ Serialize
{
fn into_delta(self) -> DeltaResult<<Self as Core>::Delta> {
let mut changes: Vec<EltDelta<T>> = vec![];
for elt in self {
changes.push(EltDelta::Add(elt.into_delta()?));
}
Ok(VecDelta(changes))
}
}
#[derive(Clone, PartialEq)]
#[derive(serde_derive::Deserialize, serde_derive::Serialize)]
pub enum EltDelta<T: Core> {
Edit {
index: usize,
item: <T as Core>::Delta,
},
Remove { count: usize },
Add(<T as Core>::Delta),
}
impl<T: Core> std::fmt::Debug for EltDelta<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match &self {
Self::Edit { index, item } => f.debug_struct("Edit")
.field("index", index)
.field("item", item)
.finish(),
Self::Remove { count } => f.debug_struct("Remove")
.field("count", count)
.finish(),
Self::Add(delta) => write!(f, "Add({:#?})", delta),
}
}
}
#[derive(Clone, PartialEq)]
#[derive(serde_derive::Deserialize, serde_derive::Serialize)]
pub struct VecDelta<T: Core>(#[doc(hidden)] pub Vec<EltDelta<T>>);
impl<T: Core> VecDelta<T> {
#[inline(always)]
pub fn iter<'d>(&'d self) -> impl Iterator<Item = &EltDelta<T>> + 'd {
self.0.iter()
}
#[inline(always)]
pub fn into_iter<'d>(self) -> impl Iterator<Item = EltDelta<T>> + 'd
where Self: 'd {
self.0.into_iter()
}
#[inline(always)]
pub fn len(&self) -> usize { self.0.len() }
}
impl<T: Core> std::fmt::Debug for VecDelta<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "VecDelta ")?;
f.debug_list().entries(self.iter()).finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(non_snake_case)]
#[test]
fn Vec__delta__same_values() -> DeltaResult<()> {
let vec0: Vec<i32> = vec![1, 3, 10, 30];
let vec1: Vec<i32> = vec![1, 3, 10, 30];
assert_eq!(vec0, vec1);
let delta = vec0.delta(&vec1)?;
assert_eq!(delta, VecDelta(vec![]));
let vec2 = vec0.apply(delta)?;
assert_eq!(vec1, vec2);
let delta = vec1.delta(&vec0)?;
assert_eq!(delta, VecDelta(vec![]));
let vec3 = vec1.apply(delta)?;
assert_eq!(vec0, vec3);
Ok(())
}
#[allow(non_snake_case)]
#[test]
fn Vec__delta__different_values__same_length() -> DeltaResult<()> {
let vec0 = vec![1, 3, 10, 49, 30, 500];
let vec1 = vec![1, 3, 10, 30, 500, 49];
let delta0 = vec0.delta(&vec1)?;
assert_eq!(delta0, VecDelta(vec![
EltDelta::Edit { index: 3, item: 30i32.into_delta()?, },
EltDelta::Edit { index: 4, item: 500i32.into_delta()?, },
EltDelta::Edit { index: 5, item: 49i32.into_delta()?, },
]));
let vec2 = vec0.apply(delta0)?;
assert_eq!(vec1, vec2);
let delta = vec1.delta(&vec0)?;
assert_eq!(delta, VecDelta(vec![
EltDelta::Edit { index: 3, item: 49i32.into_delta()?, },
EltDelta::Edit { index: 4, item: 30i32.into_delta()?, },
EltDelta::Edit { index: 5, item: 500i32.into_delta()?, },
]));
let vec3 = vec1.apply(delta)?;
assert_eq!(vec0, vec3);
Ok(())
}
#[allow(non_snake_case)]
#[test]
fn Vec__delta__different_values__different_length() -> DeltaResult<()> {
let vec0: Vec<i32> = vec![1, 3, 10, 30];
let vec1: Vec<i32> = vec![1, 3, 10, 49, 30, 500];
let delta0 = vec0.delta(&vec1)?;
assert_eq!(delta0, VecDelta(vec![
EltDelta::Edit { index: 3, item: 49.into_delta()?, },
EltDelta::Add(30.into_delta()?),
EltDelta::Add(500.into_delta()?),
]));
let vec2 = vec0.apply(delta0)?;
assert_eq!(vec1, vec2);
let delta = vec1.delta(&vec0)?;
assert_eq!(delta, VecDelta(vec![
EltDelta::Edit { index: 3, item: 30.into_delta()?, },
EltDelta::Remove { count: 2, },
]));
let vec3 = vec1.apply(delta)?;
assert_eq!(vec0, vec3);
Ok(())
}
#[allow(non_snake_case)]
#[test]
fn Vec__apply__different_values__same_length() -> DeltaResult<()> {
let vec0 = vec![1, 3, 10, 30, 30];
let vec1 = vec![1, 3, 10, 30, 40];
let delta = vec0.delta(&vec1)?;
let vec2 = vec0.apply(delta)?;
assert_eq!(vec1, vec2);
Ok(())
}
#[allow(non_snake_case)]
#[test]
fn Vec__apply__different_values__different_length() -> DeltaResult<()> {
let vec0 = vec![1, 3, 10, 30, 30];
let vec1 = vec![1, 3, 10, 30, 30, 40];
let delta = vec0.delta(&vec1)?;
let vec2 = vec0.apply(delta)?;
assert_eq!(vec1, vec2);
Ok(())
}
}