| 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 | |