similar/algorithms/
capture.rs

1use std::convert::Infallible;
2
3use crate::algorithms::DiffHook;
4use crate::{group_diff_ops, DiffOp};
5
6/// A [`DiffHook`] that captures all diff operations.
7#[derive(Default, Clone)]
8pub struct Capture(Vec<DiffOp>);
9
10impl 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
34impl 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]
96fn 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}