imara_diff/sink.rs
1use std::ops::Range;
2
3/// Trait for processing the edit-scripts computed with [`diff`](crate::diff)
4pub trait Sink: Sized {
5 type Out;
6
7 /// This method is called whenever a diff [`algorithm`](crate::Algorithm)
8 /// finds a change between the two processed input files.
9 /// A change is a continuous subsequence of [tokens](crate::intern::Token) `before` that needs
10 /// to be replaced by a different continuous subsequence of tokens `after` to construct the second file from the first.
11 ///
12 /// These token subsequences are passed to this function in in ** strictly monotonically increasing order**.
13 /// That means that for two subsequent calls `process_change(before1, after1)` and `process_change(before2, after2)`
14 /// the following always holds:
15 ///
16 /// ``` no_compile
17 /// assert!(before1.end < before2.start);
18 /// assert!(after1.end < after2.start);
19 /// ```
20 ///
21 /// # Parameters
22 /// - **`before`** - the **position** of the removed token subsequence in the orignal file.
23 /// - **`after`** - the **position** of the inserted token subsequence in the destination file.
24 ///
25 /// # Notes
26 ////
27 /// A `Sink` has no function to indicate that a section of a file remains unchanged.
28 /// However due to the monotonically increasing calls, implementations can easily determine
29 /// which subsequences remain unchanged by saving `before.end`/`after.end`.
30 /// The range between `before.start`/`after.end` and the previous `before.end`/`after.end`
31 /// is always unchanged.
32 fn process_change(&mut self, before: Range<u32>, after: Range<u32>);
33
34 /// This function is called after all calls to `process_change` are complete
35 /// to obtain the final diff result
36 fn finish(self) -> Self::Out;
37
38 /// Utility method that constructs a [`Counter`] that tracks the total number
39 /// of inserted and removed tokens in the changes passed to [`process_change`](crate::Sink::process_change).
40 fn with_counter(self) -> Counter<Self> {
41 Counter::new(self)
42 }
43}
44
45impl<T: FnMut(Range<u32>, Range<u32>)> Sink for T {
46 type Out = ();
47
48 fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
49 self(before, after)
50 }
51
52 fn finish(self) -> Self::Out {}
53}
54
55impl Sink for () {
56 type Out = ();
57 fn process_change(&mut self, _before: Range<u32>, _after: Range<u32>) {}
58 fn finish(self) -> Self::Out {}
59}
60
61/// A [`Sink`] which wraps a different sink
62/// and counts the number of `removed` and `inserted` [tokens](crate::intern::Token).
63pub struct Counter<T> {
64 /// Total number of recorded inserted [`tokens`](crate::intern::Token).
65 /// Computed by summing the lengths of the `after` subsequences pass to [`process_change`](crate::Sink::process_change).
66 pub removals: u32,
67 /// Total number of recorded inserted [`tokens`](crate::intern::Token).
68 /// Computed by summing the lengths of the `after` subsequences pass to [`process_change`](crate::Sink::process_change).
69 pub insertions: u32,
70 /// The [`Sink`] for which the counter records [`tokens`](crate::intern::Token).
71 /// All calls to [`process_change`](crate::Sink::process_change) are forwarded to the `sink` by the counter.
72 /// After [`finish`](crate::Sink::finish) is called, this field contains the output returned by the [`finish`](crate::Sink::finish)
73 /// method of the wrapped [`Sink`].
74 pub wrapped: T,
75}
76
77impl<S: Sink> Counter<S> {
78 pub fn new(sink: S) -> Self {
79 Self {
80 insertions: 0,
81 removals: 0,
82 wrapped: sink,
83 }
84 }
85}
86
87impl<S: Sink> Sink for Counter<S> {
88 type Out = Counter<S::Out>;
89 fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
90 self.removals += before.end - before.start;
91 self.insertions += after.end - after.start;
92 self.wrapped.process_change(before, after)
93 }
94
95 fn finish(self) -> Self::Out {
96 Counter {
97 removals: self.removals,
98 insertions: self.insertions,
99 wrapped: self.wrapped.finish(),
100 }
101 }
102}
103
104impl<T> Counter<T> {
105 pub fn total(&self) -> usize {
106 self.insertions as usize + self.removals as usize
107 }
108}
109
110impl Default for Counter<()> {
111 fn default() -> Self {
112 Counter::new(())
113 }
114}