use std::{cmp, ops::Range};
use self::private::Sealed;
pub type Deletion = Range<usize>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Insertion<'a, T> {
pub start: usize,
pub data: &'a [T],
}
impl<'a, T> Insertion<'a, T> {
pub fn new(start: usize, data: &'a [T]) -> Self {
Insertion { start, data }
}
pub fn to_owned(&self) -> OwnedInsertion<T>
where
T: Clone,
{
self.into()
}
}
impl<'a, T> From<&'a OwnedInsertion<T>> for Insertion<'a, T> {
fn from(owned_insertion: &'a OwnedInsertion<T>) -> Self {
Insertion::new(owned_insertion.start, &owned_insertion.data)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OwnedInsertion<T> {
pub start: usize,
pub data: Vec<T>,
}
impl<T> OwnedInsertion<T> {
pub fn new(start: usize, data: Vec<T>) -> Self {
OwnedInsertion { start, data }
}
pub fn borrow(&self) -> Insertion<T> {
self.into()
}
}
impl<T: Clone> From<&Insertion<'_, T>> for OwnedInsertion<T> {
fn from(insertion: &Insertion<T>) -> Self {
OwnedInsertion::new(insertion.start, insertion.data.to_vec())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Difference<'a, T> {
pub deletions: Vec<Deletion>,
pub insertions: Vec<Insertion<'a, T>>,
}
impl<'a, T> Difference<'a, T> {
pub fn empty() -> Self {
Difference::new(Vec::new(), Vec::new())
}
pub fn new(
deletions: Vec<Deletion>,
insertions: Vec<Insertion<'a, T>>,
) -> Self {
Difference { deletions, insertions }
}
pub fn from_deletions(deletions: Vec<Deletion>) -> Self {
deletions.into()
}
pub fn from_insertions(insertions: Vec<Insertion<'a, T>>) -> Self {
insertions.into()
}
pub fn to_owned(&self) -> OwnedDifference<T>
where
T: Clone,
{
self.into()
}
}
impl<T> From<Vec<Deletion>> for Difference<'_, T> {
fn from(deletions: Vec<Deletion>) -> Self {
Difference { deletions, insertions: Vec::new() }
}
}
impl<'a, T> From<Vec<Insertion<'a, T>>> for Difference<'a, T> {
fn from(insertions: Vec<Insertion<'a, T>>) -> Self {
Difference { deletions: Vec::new(), insertions }
}
}
impl<'a, T> From<&'a OwnedDifference<T>> for Difference<'a, T> {
fn from(owned_difference: &'a OwnedDifference<T>) -> Self {
Difference::new(
owned_difference.deletions.clone(),
owned_difference.insertions.iter().map(Into::into).collect(),
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OwnedDifference<T> {
pub deletions: Vec<Deletion>,
pub insertions: Vec<OwnedInsertion<T>>,
}
impl<T> OwnedDifference<T> {
pub fn empty() -> Self {
OwnedDifference::new(Vec::new(), Vec::new())
}
pub fn new(
deletions: Vec<Deletion>,
insertions: Vec<OwnedInsertion<T>>,
) -> Self {
OwnedDifference { deletions, insertions }
}
pub fn from_deletions(deletions: Vec<Deletion>) -> Self {
deletions.into()
}
pub fn from_insertions(insertions: Vec<OwnedInsertion<T>>) -> Self {
insertions.into()
}
pub fn borrow(&self) -> Difference<T> {
self.into()
}
}
impl<T> From<Vec<Deletion>> for OwnedDifference<T> {
fn from(deletions: Vec<Deletion>) -> Self {
OwnedDifference { deletions, insertions: Vec::new() }
}
}
impl<T> From<Vec<OwnedInsertion<T>>> for OwnedDifference<T> {
fn from(insertions: Vec<OwnedInsertion<T>>) -> Self {
OwnedDifference { deletions: Vec::new(), insertions }
}
}
impl<T: Clone> From<&Difference<'_, T>> for OwnedDifference<T> {
fn from(difference: &Difference<T>) -> Self {
OwnedDifference::new(
difference.deletions.clone(),
difference.insertions.iter().map(Into::into).collect(),
)
}
}
impl<T> Sealed for [T] {}
impl<T> Sealed for Vec<T> {}
pub trait Lcs: Sealed {
fn lcs(&self, other: &Self) -> (Vec<usize>, Vec<usize>);
}
impl<T: Eq> Lcs for [T] {
fn lcs(&self, other: &Self) -> (Vec<usize>, Vec<usize>) {
let mut lengths = vec![vec![0; other.len() + 1]; self.len() + 1];
for (index_self, value_self) in self.iter().enumerate().rev() {
for (index_other, value_other) in other.iter().enumerate().rev() {
lengths[index_self][index_other] = if value_self == value_other
{
lengths[index_self + 1][index_other + 1] + 1
} else {
cmp::max(
lengths[index_self + 1][index_other],
lengths[index_self][index_other + 1],
)
};
}
}
let mut result_self = Vec::new();
let mut result_other = Vec::new();
let mut index_self = 0;
let mut index_other = 0;
while lengths[index_self][index_other] > 0 {
if self[index_self] == other[index_other] {
result_self.push(index_self);
result_other.push(index_other);
index_self += 1;
index_other += 1;
} else if lengths[index_self + 1][index_other]
> lengths[index_self][index_other + 1]
{
index_self += 1;
} else {
index_other += 1;
}
}
(result_self, result_other)
}
}
impl<T: Eq> Lcs for Vec<T> {
fn lcs(&self, other: &Self) -> (Vec<usize>, Vec<usize>) {
(&self[..]).lcs(other)
}
}
pub trait Diff<T>: Lcs {
fn diff(&self, old: &Self) -> Difference<T>;
}
impl<T: Eq> Diff<T> for [T] {
fn diff(&self, old: &Self) -> Difference<T> {
let (lcs_old, lcs_self) = old.lcs(self);
let mut result = Difference::empty();
for index in
(0..old.len()).filter(|index| lcs_old.binary_search(index).is_err())
{
match result.deletions.last_mut() {
Some(Deletion { end, .. }) if index == *end => *end += 1,
_ => result.deletions.push(index..index + 1),
}
}
for index in (0..self.len())
.filter(|index| lcs_self.binary_search(index).is_err())
{
match result.insertions.last_mut() {
Some(Insertion { start, data })
if index == *start + data.len() =>
{
*data = &self[*start..=index];
}
_ => result
.insertions
.push(Insertion::new(index, &self[index..=index])),
}
}
result
}
}
impl<T: Eq> Diff<T> for Vec<T> {
fn diff(&self, old: &Self) -> Difference<T> {
(&self[..]).diff(old)
}
}
pub trait Patch<T>: Diff<T> {
fn patch(&mut self, diff: Difference<T>);
}
impl<T: Eq + Clone> Patch<T> for Vec<T> {
fn patch(&mut self, diff: Difference<T>) {
let Difference { deletions, insertions } = diff;
for deletion in deletions.into_iter().rev() {
self.drain(deletion);
}
for Insertion { start, data } in insertions {
self.splice(start..start, data.iter().map(Clone::clone));
}
}
}
pub trait Patched<T>: Diff<T> {
fn patched(&self, diff: Difference<T>) -> Vec<T>;
}
impl<T: Eq + Clone> Patched<T> for [T] {
fn patched(&self, diff: Difference<T>) -> Vec<T> {
let mut vec = self.to_vec();
vec.patch(diff);
vec
}
}
impl<T: Eq + Clone> Patched<T> for Vec<T> {
fn patched(&self, diff: Difference<T>) -> Vec<T> {
(&self[..]).patched(diff)
}
}
mod private {
pub trait Sealed {}
}
#[cfg(test)]
mod tests {
use super::{Diff, Difference, Insertion, Lcs, Patched};
#[test]
fn lcs() {
let (left_lcs, right_lcs) = b"BANANA".lcs(b"ATANA");
assert_eq!(left_lcs, [1, 3, 4, 5]);
assert_eq!(right_lcs, [0, 2, 3, 4]);
let (left_lcs, right_lcs) = b"abc".lcs(b"ABC");
assert_eq!(left_lcs, []);
assert_eq!(right_lcs, []);
let (left_lcs, right_lcs) = b"ABC".lcs(b"ABC");
assert_eq!(left_lcs, [0, 1, 2]);
assert_eq!(right_lcs, [0, 1, 2]);
let (left_lcs, right_lcs) = b"ABC".lcs(b"");
assert_eq!(left_lcs, []);
assert_eq!(right_lcs, []);
let (left_lcs, right_lcs) = b"".lcs(b"");
assert_eq!(left_lcs, []);
assert_eq!(right_lcs, []);
}
#[test]
fn diff() {
assert_eq!(
b"ATANA".diff(b"BANANA"),
Difference::new(vec![0..1, 2..3], vec![Insertion::new(1, b"T")],)
);
assert_eq!(
b"2345".diff(b"012389"),
Difference::new(vec![0..2, 4..6], vec![Insertion::new(2, b"45")],)
);
assert_eq!(
b"72345".diff(b"012389"),
Difference::new(
vec![0..2, 4..6],
vec![Insertion::new(0, b"7"), Insertion::new(3, b"45")],
)
);
}
#[test]
fn patch() {
let old = b"BANANA";
let new = b"ATANA";
assert_eq!(old.patched(new.diff(old)), new);
let old = b"012389";
let new = b"2345";
assert_eq!(old.patched(new.diff(old)), new);
let old = b"012389";
let new = b"72345";
assert_eq!(old.patched(new.diff(old)), new);
}
}