1 | use std::convert::Infallible; |
2 | |
3 | use crate::algorithms::DiffHook; |
4 | use crate::{group_diff_ops, DiffOp}; |
5 | |
6 | /// A [`DiffHook`] that captures all diff operations. |
7 | #[derive (Default, Clone)] |
8 | pub struct Capture(Vec<DiffOp>); |
9 | |
10 | impl Capture { |
11 | /// Creates a new capture hook. |
12 | pub fn new() -> Capture { |
13 | Capture::default() |
14 | } |
15 | |
16 | /// Converts the capture hook into a vector of ops. |
17 | pub fn into_ops(self) -> Vec<DiffOp> { |
18 | self.0 |
19 | } |
20 | |
21 | /// Isolate change clusters by eliminating ranges with no changes. |
22 | /// |
23 | /// This is equivalent to calling [`group_diff_ops`] on [`Capture::into_ops`]. |
24 | pub fn into_grouped_ops(self, n: usize) -> Vec<Vec<DiffOp>> { |
25 | group_diff_ops(self.into_ops(), n) |
26 | } |
27 | |
28 | /// Accesses the captured operations. |
29 | pub fn ops(&self) -> &[DiffOp] { |
30 | &self.0 |
31 | } |
32 | } |
33 | |
34 | impl DiffHook for Capture { |
35 | type Error = Infallible; |
36 | |
37 | #[inline (always)] |
38 | fn equal(&mut self, old_index: usize, new_index: usize, len: usize) -> Result<(), Self::Error> { |
39 | self.0.push(DiffOp::Equal { |
40 | old_index, |
41 | new_index, |
42 | len, |
43 | }); |
44 | Ok(()) |
45 | } |
46 | |
47 | #[inline (always)] |
48 | fn delete( |
49 | &mut self, |
50 | old_index: usize, |
51 | old_len: usize, |
52 | new_index: usize, |
53 | ) -> Result<(), Self::Error> { |
54 | self.0.push(DiffOp::Delete { |
55 | old_index, |
56 | old_len, |
57 | new_index, |
58 | }); |
59 | Ok(()) |
60 | } |
61 | |
62 | #[inline (always)] |
63 | fn insert( |
64 | &mut self, |
65 | old_index: usize, |
66 | new_index: usize, |
67 | new_len: usize, |
68 | ) -> Result<(), Self::Error> { |
69 | self.0.push(DiffOp::Insert { |
70 | old_index, |
71 | new_index, |
72 | new_len, |
73 | }); |
74 | Ok(()) |
75 | } |
76 | |
77 | #[inline (always)] |
78 | fn replace( |
79 | &mut self, |
80 | old_index: usize, |
81 | old_len: usize, |
82 | new_index: usize, |
83 | new_len: usize, |
84 | ) -> Result<(), Self::Error> { |
85 | self.0.push(DiffOp::Replace { |
86 | old_index, |
87 | old_len, |
88 | new_index, |
89 | new_len, |
90 | }); |
91 | Ok(()) |
92 | } |
93 | } |
94 | |
95 | #[test ] |
96 | fn test_capture_hook_grouping() { |
97 | use crate::algorithms::{diff_slices, Algorithm, Replace}; |
98 | |
99 | let rng = (1..100).collect::<Vec<_>>(); |
100 | let mut rng_new = rng.clone(); |
101 | rng_new[10] = 1000; |
102 | rng_new[13] = 1000; |
103 | rng_new[16] = 1000; |
104 | rng_new[34] = 1000; |
105 | |
106 | let mut d = Replace::new(Capture::new()); |
107 | diff_slices(Algorithm::Myers, &mut d, &rng, &rng_new).unwrap(); |
108 | |
109 | let ops = d.into_inner().into_grouped_ops(3); |
110 | let tags = ops |
111 | .iter() |
112 | .map(|group| group.iter().map(|x| x.as_tag_tuple()).collect::<Vec<_>>()) |
113 | .collect::<Vec<_>>(); |
114 | |
115 | insta::assert_debug_snapshot!(ops); |
116 | insta::assert_debug_snapshot!(tags); |
117 | } |
118 | |