#![deny(missing_docs)]
#![deny(clippy::all)]
pub mod prelude;
#[derive(Debug, Hash, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum Diff<T> {
Change(T),
Remove,
Keep,
Add(T),
}
#[derive(Debug, Hash, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub struct DiffIter<Lhs, Rhs> {
lhs: Lhs,
rhs: Rhs,
}
impl<T, U, Lhs, Rhs> Iterator for DiffIter<Lhs, Rhs>
where
T: PartialEq<U>,
Lhs: Iterator<Item = T>,
Rhs: Iterator<Item = U>,
{
type Item = Diff<U>;
fn next(&mut self) -> Option<Self::Item> {
let l = self.lhs.next();
let r = self.rhs.next();
match (l, r) {
(None, None) => None,
(None, Some(r)) => Some(Diff::Add(r)),
(Some(_), None) => Some(Diff::Remove),
(Some(l), Some(r)) => match l == r {
true => Some(Diff::Keep),
false => Some(Diff::Change(r)),
},
}
}
}
pub trait IterDiff<T>: IntoIterator<Item = T> + sealed::Sealed<T> {
fn iter_diff<U, Rhs>(
self,
rhs: Rhs,
) -> DiffIter<Self::IntoIter, Rhs::IntoIter>
where
T: PartialEq<U>,
Rhs: IntoIterator<Item = U>;
}
impl<T, Lhs> IterDiff<T> for Lhs
where
Lhs: IntoIterator<Item = T>,
{
fn iter_diff<U, Rhs>(
self,
rhs: Rhs,
) -> DiffIter<Lhs::IntoIter, Rhs::IntoIter>
where
T: PartialEq<U>,
Rhs: IntoIterator<Item = U>,
{
let lhs = self.into_iter();
let rhs = rhs.into_iter();
DiffIter { lhs, rhs }
}
}
mod sealed {
pub trait Sealed<T> {}
impl<T, I> Sealed<T> for I where I: IntoIterator<Item = T> {}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn remove() {
let a = [0, 1, 2, 4];
let b = [0, 2];
let diffs: Vec<_> = a.iter_diff(b).collect();
assert_eq!(diffs.len(), 4);
assert_eq!(diffs[0], Diff::Keep);
assert_eq!(diffs[1], Diff::Change(2));
assert_eq!(diffs[2], Diff::Remove);
assert_eq!(diffs[3], Diff::Remove);
}
#[test]
fn add() {
let a = [0, 2];
let b = [0, 1, 2, 4];
let diffs: Vec<_> = a.iter_diff(b).collect();
assert_eq!(diffs.len(), 4);
assert_eq!(diffs[0], Diff::Keep);
assert_eq!(diffs[1], Diff::Change(1));
assert_eq!(diffs[2], Diff::Add(2));
assert_eq!(diffs[3], Diff::Add(4));
}
#[test]
fn multi_change() {
let a = [0, 1, 2, 3];
let b = [0, 3, 1, 3];
let diffs: Vec<_> = a.iter_diff(b).collect();
assert_eq!(diffs.len(), 4);
assert_eq!(diffs[0], Diff::Keep);
assert_eq!(diffs[1], Diff::Change(3));
assert_eq!(diffs[2], Diff::Change(1));
assert_eq!(diffs[3], Diff::Keep);
}
struct TestInt(i32);
impl PartialEq<i32> for TestInt {
fn eq(&self, other: &i32) -> bool {
self.0 == *other
}
}
#[test]
fn add_mixed() {
let a = [TestInt(0), TestInt(2)];
let b = [0, 1, 2, 4];
let diffs: Vec<_> = a.iter_diff(b).collect();
assert_eq!(diffs.len(), 4);
assert_eq!(diffs[0], Diff::Keep);
assert_eq!(diffs[1], Diff::Change(1));
assert_eq!(diffs[2], Diff::Add(2));
assert_eq!(diffs[3], Diff::Add(4));
}
}