1use std::io::Write;
2
3use enum_to_string::EnumToString;
4use flate2::write::{DeflateDecoder, DeflateEncoder};
5use flate2::Compression;
6use serde::{Deserialize, Serialize};
7
8use crate::Result;
9
10pub const DEFAULT_AXIS_BOUNDARY_LEN: usize = 36;
11
12#[derive(EnumToString, Clone, Copy, Deserialize, Serialize)]
13pub enum DiffType {
14 Binary,
15 Text,
16}
17#[derive(Debug, Clone, Copy, Deserialize, Serialize, Hash, PartialEq, PartialOrd, Eq, Ord)]
18pub enum LineTermination {
19 CR,
20 LF,
21 CRLF,
22}
23impl Default for LineTermination {
24 fn default() -> LineTermination {
25 LineTermination::CRLF
26 }
27}
28
29#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, PartialOrd, Ord, Eq)]
30pub enum AxisBoundary {
31 Len(usize),
32 }
37impl Default for AxisBoundary {
38 fn default() -> AxisBoundary {
39 AxisBoundary::Len(DEFAULT_AXIS_BOUNDARY_LEN)
40 }
41}
42
43#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, PartialOrd, Eq, Ord)]
44pub struct DiffSettings {
45 pub axis_boundary: AxisBoundary,
46}
47impl Default for DiffSettings {
48 fn default() -> DiffSettings {
49 DiffSettings {
50 axis_boundary: AxisBoundary::default(),
51 }
52 }
53}
54
55#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, PartialOrd, Eq, Ord)]
56pub struct DiffUnit {
57 pub x: usize,
58 pub y: usize,
59 pub anterior: Vec<u8>,
60 pub current: Vec<u8>,
61}
62impl DiffUnit {
63 pub fn new(anterior: Option<u8>, current: Option<u8>, x: usize, y: usize) -> DiffUnit {
64 DiffUnit {
65 x,
66 y,
67 anterior: anterior.map(|byte| vec![byte]).unwrap_or_default(),
68 current: current.map(|byte| vec![byte]).unwrap_or_default(),
69 }
70 }
71
72 pub fn anterior(&self) -> Option<u8> {
73 self.anterior.get(0).copied()
74 }
75
76 pub fn current(&self) -> Option<u8> {
77 self.current.get(0).copied()
78 }
79}
80
81#[derive(Clone, Deserialize, Serialize, Hash, PartialEq, PartialOrd, Eq, Ord, Debug)]
82pub struct Diff {
83 pub sequence: Vec<DiffUnit>,
84 pub settings: DiffSettings,
85}
86impl Default for Diff {
87 fn default() -> Diff {
88 Diff {
89 sequence: Vec::new(),
90 settings: DiffSettings::default(),
91 }
92 }
93}
94impl Diff {
95 pub fn new(axis_boundary: AxisBoundary) -> Diff {
96 Diff {
97 sequence: Vec::new(),
98 settings: DiffSettings { axis_boundary },
99 }
100 }
101
102 pub fn to_bytes(&self) -> Result<Vec<u8>> {
103 let bytes = bincode::serialize(self)?;
104 Ok(bytes)
105 }
106
107 pub fn from_bytes(bytes: &[u8]) -> Result<Diff> {
108 let diff: Diff = bincode::deserialize(bytes)?;
109 Ok(diff)
110 }
111
112 pub fn to_flate_bytes(&self) -> Result<Vec<u8>> {
113 let mut e = DeflateEncoder::new(Vec::new(), Compression::best());
114 e.write(&self.to_bytes()?)?;
115 Ok(e.finish()?)
116 }
117
118 pub fn from_deflate_bytes(bytes: &[u8]) -> Result<Diff> {
119 let mut d = DeflateDecoder::new(Vec::new());
120 d.write(bytes)?;
121 let deflated = d.finish()?;
122 Ok(Diff::from_bytes(&deflated)?)
123 }
124
125 pub fn anterior_version(&self) -> Vec<u8> {
126 self.sequence
127 .iter()
128 .filter(|unit| unit.anterior().is_some())
129 .map(|unit| unit.anterior().unwrap())
130 .collect()
131 }
132
133 pub fn current_version(&self) -> Vec<u8> {
134 self.sequence
135 .iter()
136 .filter(|unit| unit.current().is_some())
137 .map(|unit| unit.current().unwrap())
138 .collect()
139 }
140
141 pub fn update(&mut self, data: &[u8]) -> Result<Vec<u8>> {
142 let anterior = self.anterior_version();
143 let current = self.current_version();
144 let diff = diff(¤t, data, self.axis_boundary())?;
145 self.sequence = diff.sequence.clone();
146 Ok(anterior)
147 }
148
149 pub fn axis_boundary(&self) -> AxisBoundary {
150 self.settings.axis_boundary.clone()
151 }
152
153 pub fn digest_anterior_version<A: digest::Digest>(&self) -> Vec<u8> {
154 let mut sha3 = A::new();
155 sha3.update(&self.anterior_version());
156 sha3.finalize().to_vec()
157 }
158
159 pub fn digest_current_version<A: digest::Digest>(&self) -> Vec<u8> {
160 let mut sha3 = A::new();
161 sha3.update(&self.current_version());
162 sha3.finalize().to_vec()
163 }
164
165 pub fn digest<A: digest::Digest>(&self) -> Vec<u8> {
166 xor(
167 &self.digest_anterior_version::<A>().to_vec(),
168 &self.digest_current_version::<A>().to_vec(),
169 )
170 }
171
172 pub fn render(&self) -> String {
173 let mut chunks = Vec::<String>::new();
174
175 for (index, chunk) in match self.settings.axis_boundary {
176 AxisBoundary::Len(length) => self
177 .sequence
178 .clone()
179 .chunks(length)
180 .map(|units| {
181 units
182 .iter()
183 .map(|unit| unit.clone())
184 .collect::<Vec<DiffUnit>>()
185 })
186 .collect::<Vec<Vec<DiffUnit>>>(),
187 }
188 .iter()
189 .enumerate()
190 {
191 let mut temp_chunks = Vec::<Vec<String>>::new();
192 let mut changes = false;
193 for unit in chunk {
194 let anterior = unit.anterior();
195 let current = unit.current();
196 if anterior != current {
197 changes = true;
198 temp_chunks.push(vec![
199 format!("\x1b[0;31m0x{:02x}\x1b[0m", anterior.unwrap_or_default()),
200 format!("\x1b[0;32m0x{:02x}\x1b[0m", current.unwrap_or_default()),
201 ]);
202 } else {
203 temp_chunks.push(vec![format!(
204 "0x{:02x}",
205 anterior.or(current).unwrap_or_default()
206 )]);
207 }
208 }
209 if changes {
210 chunks.push(format!(
211 "\x1b[0;31m-0x{:07x}\x1b[0m {}",
212 index,
213 temp_chunks
214 .iter()
215 .map(|chunk| chunk[0].to_string())
216 .collect::<Vec<String>>()
217 .join(" ")
218 ));
219 chunks.push(format!(
220 "\x1b[0;32m+0x{:07x}\x1b[0m {}",
221 index,
222 temp_chunks
223 .iter()
224 .map(|chunk| if chunk.len() > 1 {
225 chunk[1].to_string()
226 } else {
227 chunk[0].to_string()
228 }
229 .to_string())
230 .collect::<Vec<String>>()
231 .join(" ")
232 ));
233 } else {
234 chunks.push(format!(
235 " 0x{:07x} {}",
236 index,
237 temp_chunks
238 .iter()
239 .map(|chunk| chunk.join(""))
240 .collect::<Vec<String>>()
241 .join(" ")
242 ));
243 }
244 }
245 chunks.join("\n")
246 }
247}
248
249pub fn diff(anterior: &[u8], current: &[u8], axis_boundary: AxisBoundary) -> Result<Diff> {
250 match axis_boundary {
251 AxisBoundary::Len(len) => diff_len(anterior, current, len),
252 }
254}
255
256pub fn diff_len(anterior: &[u8], current: &[u8], axis_boundary_len: usize) -> Result<Diff> {
257 let mut diff = Vec::<DiffUnit>::new();
258 for (y, chunk) in zip_chunked(anterior, current, axis_boundary_len)
259 .iter()
260 .enumerate()
261 {
262 for (x, (anterior, current)) in chunk.iter().enumerate() {
263 let anterior = *anterior;
264 let current = *current;
265 diff.push(DiffUnit::new(anterior, current, x, y));
266 }
267 }
268 Ok(Diff {
269 sequence: diff,
270 settings: DiffSettings {
271 axis_boundary: AxisBoundary::Len(axis_boundary_len),
272 },
273 })
274}
275
276fn optional_max_bytes(items: &[u8], chunk_size: usize) -> Vec<Option<u8>> {
277 let rem = rem(items, chunk_size);
278 let mut items = items
279 .iter()
280 .map(|byte| Some(*byte))
281 .collect::<Vec<Option<u8>>>();
282 for _ in 0..rem {
283 items.push(None)
284 }
285 items
286}
287
288fn zip_max_modulus(x: &[u8], y: &[u8], chunk_size: usize) -> Vec<(Option<u8>, Option<u8>)> {
289 let max_len = [x.len(), y.len()].iter().max().map(|n| *n).unwrap_or(0);
290 let mut x = optional_max_bytes(x, chunk_size);
291 if x.len() < max_len {
292 for _ in 0..(max_len - x.len()) {
293 x.push(None)
294 }
295 }
296 let mut y = optional_max_bytes(y, chunk_size);
297 if y.len() < max_len {
298 for _ in 0..(max_len - y.len()) {
299 y.push(None)
300 }
301 }
302 x.iter()
303 .zip(y)
304 .map(|(x, y)| (*x, y))
305 .collect::<Vec<(Option<u8>, Option<u8>)>>()
306}
307
308fn zip_chunked(x: &[u8], y: &[u8], chunk_size: usize) -> Vec<Vec<(Option<u8>, Option<u8>)>> {
309 let mut chunked = Vec::<Vec<(Option<u8>, Option<u8>)>>::new();
310 for chunk in zip_max_modulus(x, y, chunk_size).chunks(chunk_size) {
311 let tchunks = chunk
312 .iter()
313 .map(|possible| *possible)
314 .collect::<Vec<(Option<u8>, Option<u8>)>>();
315 chunked.push(tchunks);
316 }
317 chunked
318}
319pub(crate) fn rem(items: &[u8], chunk_size: usize) -> usize {
320 if items.len() > chunk_size {
321 items.len() % chunk_size
322 } else if items.len() > 0 && chunk_size > items.len() {
323 chunk_size % items.len()
324 } else {
325 0
326 }
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332
333 #[test]
334 fn test_rem() {
335 let data = vec![0x01, 0x10, 0xF1, 0x61];
336 assert_eq!(rem(&data, 6), 2);
337 let data = vec![0x01, 0x10, 0xF1, 0x61, 0x01, 0x10, 0xF1, 0x61];
338 assert_eq!(rem(&data, 6), 2);
339 let data = vec![];
340 assert_eq!(rem(&data, 6), 0);
341 }
342
343 #[test]
344 fn test_optional_max_bytes() {
345 let anterior = vec![
346 0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, 0x20, 0x21, 0x23, 0x30, 0x31, 0x32,
347 0x33,
348 ];
349
350 assert_eq!(
351 optional_max_bytes(&anterior, 4),
352 vec![
353 Some(0x00),
354 Some(0x01),
355 Some(0x02),
356 Some(0x03),
357 Some(0x10),
358 Some(0x11),
359 Some(0x12),
360 Some(0x13),
361 Some(0x20),
362 Some(0x21),
363 Some(0x23),
364 Some(0x30),
365 Some(0x31),
366 Some(0x32),
367 Some(0x33),
368 None,
369 None,
370 None,
371 ],
372 )
373 }
374
375 #[test]
376 fn test_zip_max_modulus() {
377 let anterior = vec![0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12];
378 let current = vec![0x13, 0x20, 0x21, 0x23, 0x30, 0x31, 0x32, 0x33];
379
380 assert_eq!(
381 zip_max_modulus(&anterior, ¤t, 4),
382 vec![
383 (Some(0x00), Some(0x13)),
384 (Some(0x01), Some(0x20)),
385 (Some(0x02), Some(0x21)),
386 (Some(0x03), Some(0x23)),
387 (Some(0x10), Some(0x30)),
388 (Some(0x11), Some(0x31)),
389 (Some(0x12), Some(0x32)),
390 (None, Some(0x33)),
391 ]
392 )
393 }
394 #[test]
395 fn test_zip_chunked_max_len() {
396 let anterior = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
397 let current = vec![0x00, 0x00, 0x02];
398 assert_eq!(
399 zip_chunked(&anterior, ¤t, 2),
400 vec![
401 vec![(Some(0x00), Some(0x00)), (Some(0x00), Some(0x00))],
402 vec![(Some(0x00), Some(0x02)), (Some(0x00), None)],
403 vec![(Some(0x00), None), (Some(0x00), None)],
404 ]
405 );
406 }
407 #[test]
408 fn test_zip_chunked() {
409 let anterior = vec![0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12];
410 let current = vec![0x13, 0x20, 0x21, 0x23, 0x30, 0x31, 0x32, 0x33];
411
412 assert_eq!(
413 zip_chunked(&anterior, ¤t, 4),
414 vec![
415 vec![
416 (Some(0x00), Some(0x13)),
417 (Some(0x01), Some(0x20)),
418 (Some(0x02), Some(0x21)),
419 (Some(0x03), Some(0x23)),
420 ],
421 vec![
422 (Some(0x10), Some(0x30)),
423 (Some(0x11), Some(0x31)),
424 (Some(0x12), Some(0x32)),
425 (None, Some(0x33))
426 ]
427 ]
428 )
429 }
430}
431
432pub fn xor(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
433 a.into_iter().zip(b.iter()).map(|(a, b)| a ^ b).collect()
434}