1#![no_std]
2
3pub trait DiffInPlace<T, const N: usize>
4where
5 T: PartialEq,
6{
7 fn try_diff_in_place<F, R>(&self, other: &[T; N], func: F) -> Result<(), R>
32 where
33 F: FnMut(usize, &[T]) -> Result<(), R>;
34
35 fn diff_in_place<F>(&self, other: &[T; N], mut func: F)
57 where
58 F: FnMut(usize, &[T]),
59 {
60 self.try_diff_in_place(other, |idx, diff| -> Result<(), ()> {
61 func(idx, diff);
62 Ok(())
63 })
64 .unwrap();
65 }
66}
67
68#[derive(Copy, Clone)]
69enum DiffState {
70 Same,
71 Different(usize),
72}
73
74impl<T, const N: usize> DiffInPlace<T, N> for [T; N]
75where
76 T: PartialEq + Copy,
77{
78 fn try_diff_in_place<F, R>(&self, other: &[T; N], mut func: F) -> Result<(), R>
79 where
80 F: FnMut(usize, &[T]) -> Result<(), R>,
81 {
82 let byte_for_byte = self.iter().zip(other.iter());
86 let mut run_state = DiffState::Same;
87 for (current, (left, right)) in byte_for_byte.enumerate() {
88 match (run_state, left == right) {
89 (DiffState::Same, false) => {
90 run_state = DiffState::Different(current);
92 }
93 (DiffState::Different(run_start), true) => {
94 func(run_start, &other[run_start..current])?;
96 run_state = DiffState::Same;
97 }
98 _ => {
99 }
101 }
102 }
103
104 if let DiffState::Different(run_start) = run_state {
106 func(run_start, &other[run_start..])?;
107 }
108
109 Ok(())
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_fully_same() {
119 let a = [0u8; 40];
120 let b = [0u8; 40];
121 a.diff_in_place(&b, |_, _| panic!("Should not be called"))
122 }
123
124 #[test]
125 fn test_fully_different() {
126 let a = [0u8; 40];
127 let b = [1u8; 40];
128
129 let mut called = false;
130 a.diff_in_place(&b, |idx, diff| {
131 assert_eq!(idx, 0);
132 assert_eq!(diff, &[1u8; 40]);
133 called = true;
134 });
135 assert!(called);
136 }
137
138 #[test]
139 fn test_start_different() {
140 let a = [0u8; 40];
141 let mut b = [0u8; 40];
142
143 b[..10].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
144
145 const EXPECTED_CALLS: [(usize, &[u8]); 1] = [(0usize, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])];
146
147 let mut called = false;
148 a.diff_in_place(&b, |idx, diff| {
149 let (expected_idx, expected_diff) = EXPECTED_CALLS[0];
150 assert_eq!(idx, expected_idx);
151 assert_eq!(diff, expected_diff);
152 called = true;
153 });
154 assert!(called);
155 }
156
157 #[test]
158 fn test_middle_different() {
159 let a = [0u8; 40];
160 let mut b = [0u8; 40];
161
162 b[10..20].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
163
164 const EXPECTED_CALLS: [(usize, &[u8]); 1] = [(10usize, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])];
165
166 let mut called = false;
167 a.diff_in_place(&b, |idx, diff| {
168 let (expected_idx, expected_diff) = EXPECTED_CALLS[0];
169 assert_eq!(idx, expected_idx);
170 assert_eq!(diff, expected_diff);
171 called = true;
172 });
173 assert!(called);
174 }
175
176 #[test]
177 fn test_end_different() {
178 let a = [0u8; 40];
179 let mut b = [0u8; 40];
180
181 b[30..].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
182
183 const EXPECTED_CALLS: [(usize, &[u8]); 1] = [(30usize, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])];
184
185 let mut called = false;
186 a.diff_in_place(&b, |idx, diff| {
187 let (expected_idx, expected_diff) = EXPECTED_CALLS[0];
188 assert_eq!(idx, expected_idx);
189 assert_eq!(diff, expected_diff);
190 called = true;
191 });
192 assert!(called);
193 }
194
195 #[test]
196 fn test_multiple_different() {
197 let a = [0u8; 40];
198 let mut b = [0u8; 40];
199
200 b[..10].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
201 b[20..25].copy_from_slice(&[11, 12, 13, 14, 15]);
202 b[39] = 20;
203
204 const EXPECTED_CALLS: [(usize, &[u8]); 3] = [
205 (0usize, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
206 (20usize, &[11, 12, 13, 14, 15]),
207 (39usize, &[20]),
208 ];
209
210 let mut call_idx = 0;
211 let mut called = false;
212 a.diff_in_place(&b, |idx, diff| {
213 let (expected_idx, expected_diff) = EXPECTED_CALLS[call_idx];
214 assert_eq!(idx, expected_idx);
215 assert_eq!(diff, expected_diff);
216 call_idx += 1;
217 called = true;
218 });
219 assert!(called);
220 }
221
222 #[test]
223 fn test_other_types() {
224 let a = [0.0f32; 40];
225 let mut b = [0.0f32; 40];
226
227 b[..10].copy_from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7., 8., 9., 10.]);
228
229 const EXPECTED_CALLS: [(usize, &[f32]); 1] =
230 [(0usize, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7., 8., 9., 10.])];
231
232 let mut called = false;
233 a.diff_in_place(&b, |idx, diff| {
234 let (expected_idx, expected_diff) = EXPECTED_CALLS[0];
235 assert_eq!(idx, expected_idx);
236 assert_eq!(diff, expected_diff);
237 called = true;
238 });
239 assert!(called);
240 }
241
242 #[test]
243 #[should_panic]
244 fn test_fallible_diff() {
245 let a = [0u8; 40];
246 let mut b = [0u8; 40];
247
248 b[..10].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
249
250 a.try_diff_in_place(&b, |_idx, _diff| -> Result<(), ()> { Err(()) })
251 .unwrap();
252 }
253}