#![no_std]
pub trait DiffInPlace<T, const N: usize>
where
T: PartialEq,
{
fn diff_in_place<F>(&self, other: &[T; N], func: F)
where
F: FnMut(usize, &[T]);
}
#[derive(Copy, Clone)]
enum DiffState {
Same,
Different(usize),
}
impl<T, const N: usize> DiffInPlace<T, N> for [T; N]
where
T: PartialEq + Copy,
{
fn diff_in_place<F>(&self, other: &[T; N], mut func: F)
where
F: FnMut(usize, &[T]),
{
let byte_for_byte = self.iter().zip(other.iter());
let mut run_state = DiffState::Same;
for (current, (left, right)) in byte_for_byte.enumerate() {
match (run_state, left == right) {
(DiffState::Same, false) => {
run_state = DiffState::Different(current);
}
(DiffState::Different(run_start), true) => {
func(run_start, &other[run_start..current]);
run_state = DiffState::Same;
}
_ => {
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fully_same() {
let a = [0u8; 40];
let b = [0u8; 40];
a.diff_in_place(&b, |_, _| panic!("Should not be called"));
}
#[test]
fn test_fully_different() {
let a = [0u8; 40];
let b = [1u8; 40];
a.diff_in_place(&b, |idx, diff| {
assert_eq!(idx, 0);
assert_eq!(diff, &[1u8]);
});
}
#[test]
fn test_start_different() {
let a = [0u8; 40];
let mut b = [0u8; 40];
b[..10].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
const EXPECTED_CALLS: [(usize, &[u8]); 1] = [(0usize, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])];
a.diff_in_place(&b, |idx, diff| {
let (expected_idx, expected_diff) = EXPECTED_CALLS[0];
assert_eq!(idx, expected_idx);
assert_eq!(diff, expected_diff);
});
}
#[test]
fn test_middle_different() {
let a = [0u8; 40];
let mut b = [0u8; 40];
b[10..20].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
const EXPECTED_CALLS: [(usize, &[u8]); 1] = [(10usize, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])];
a.diff_in_place(&b, |idx, diff| {
let (expected_idx, expected_diff) = EXPECTED_CALLS[0];
assert_eq!(idx, expected_idx);
assert_eq!(diff, expected_diff);
});
}
#[test]
fn test_end_different() {
let a = [0u8; 40];
let mut b = [0u8; 40];
b[30..].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
const EXPECTED_CALLS: [(usize, &[u8]); 1] = [(30usize, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])];
a.diff_in_place(&b, |idx, diff| {
let (expected_idx, expected_diff) = EXPECTED_CALLS[0];
assert_eq!(idx, expected_idx);
assert_eq!(diff, expected_diff);
});
}
#[test]
fn test_multiple_different() {
let a = [0u8; 40];
let mut b = [0u8; 40];
b[..10].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
b[20..25].copy_from_slice(&[11, 12, 13, 14, 15]);
b[39] = 20;
const EXPECTED_CALLS: [(usize, &[u8]); 3] = [
(0usize, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
(20usize, &[11, 12, 13, 14, 15]),
(39usize, &[20]),
];
let mut call_idx = 0;
a.diff_in_place(&b, |idx, diff| {
let (expected_idx, expected_diff) = EXPECTED_CALLS[call_idx];
assert_eq!(idx, expected_idx);
assert_eq!(diff, expected_diff);
call_idx += 1;
});
}
#[test]
fn test_other_types() {
let a = [0.0f32; 40];
let mut b = [0.0f32; 40];
b[..10].copy_from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7., 8., 9., 10.]);
const EXPECTED_CALLS: [(usize, &[f32]); 1] =
[(0usize, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7., 8., 9., 10.])];
a.diff_in_place(&b, |idx, diff| {
let (expected_idx, expected_diff) = EXPECTED_CALLS[0];
assert_eq!(idx, expected_idx);
assert_eq!(diff, expected_diff);
});
}
}