use crate::{
core::{Pos, Rect},
ops::{ExactSizeGrid, GridRead, layout::Layout as _},
};
pub trait GridDiff: GridRead + ExactSizeGrid {
fn diff<'a>(&'a self, other: &'a Self) -> impl Iterator<Item = (Pos, Self::Element<'a>)> + 'a
where
Self::Element<'a>: PartialEq;
}
impl<G> GridDiff for G
where
G: GridRead + ExactSizeGrid,
{
fn diff<'a>(&'a self, other: &'a Self) -> impl Iterator<Item = (Pos, Self::Element<'a>)> + 'a
where
Self::Element<'a>: PartialEq,
{
let same_size = self.width() == other.width() && self.height() == other.height();
let full_rect = Rect::from_ltwh(0, 0, self.width(), self.height());
Self::Layout::iter_pos(full_rect).filter_map(move |pos| {
let current = self.get(pos)?;
if same_size {
let previous = other.get(pos)?;
if current == previous {
return None;
}
}
Some((pos, current))
})
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use crate::{buf::GridBuf, core::Pos, ops::GridDiff as _};
use alloc::vec::Vec;
#[test]
fn diff_same_grid() {
let a = GridBuf::new_filled(3, 3, 0u8);
let b = GridBuf::new_filled(3, 3, 0u8);
assert!(a.diff(&b).next().is_none());
}
#[test]
fn diff_one_changed_cell() {
let a = GridBuf::new_filled(3, 3, 0u8);
let mut b = GridBuf::new_filled(3, 3, 0u8);
b[Pos::new(1, 1)] = 42;
let changed: Vec<_> = a.diff(&b).collect();
assert_eq!(changed, [(Pos::new(1, 1), &0u8)]);
}
#[test]
fn diff_all_changed() {
let a = GridBuf::new_filled(3, 3, 0u8);
let b = GridBuf::new_filled(3, 3, 1u8);
let changed: Vec<_> = a.diff(&b).collect();
assert_eq!(changed.len(), 9);
assert!(changed.iter().all(|&(_, v)| *v == 0));
}
#[test]
fn diff_different_sizes() {
let a = GridBuf::new_filled(2, 2, 0u8);
let b = GridBuf::new_filled(3, 3, 0u8);
assert_eq!(a.diff(&b).count(), 4);
}
}