1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::ops::Range;

/// Trait for processing the edit-scripts computed with [`diff`](crate::diff)
pub trait Sink: Sized {
    type Out;

    /// This method is called whenever a diff [`algorithm`](crate::Algorithm)
    /// finds a change between the two processed input file.
    /// A change is a continous subsequence of [tokens](crate::intern::Token) `before` that needs
    /// to be replaced by a different contious subsequence of tokens `after` to construct the seconds file from the first.
    ///
    /// These token subsequences are passed to this function in in ** strictly montonically increasing order**.
    /// That means that for two subsequenct  calls `process_change(before1, after1)` and `process_change(before2, after2)`
    /// the following always holds:
    ///
    /// ``` no_compile
    /// assert!(before1.end < before2.start);
    /// assert!(after1.end < after2.start);
    /// ```
    ///
    /// # Paramters
    /// - **`before`** - the **position** of the removed token subsequence in the orignal file.
    /// - **`after`** - the **position** of the inserted token subsequence in the destination file.
    ///
    /// # Notes
    ////
    /// A `Sink` has no function to indicate that  a section of a file remains unchanged.
    /// However due to the montonically increasing calls, implementations can easily determine
    /// which subsequences remain unchanged by saving `before.end`/`after.end`.
    /// The range between `before.start`/`after.end` and the previous `before.end`/`after.end`
    /// is always unchanged.
    fn process_change(&mut self, before: Range<u32>, after: Range<u32>);

    /// This function is called after all calls to `process_change` are complete
    /// to obtain the final diff result
    fn finish(self) -> Self::Out;

    /// Utility method that constructs a [`Counter`] that tracks the total number
    /// of inserted and removed tokens in the changes passed to [`process_change`](crate::Sink::process_change).
    fn with_counter(self) -> Counter<Self> {
        Counter::new(self)
    }
}

impl<T: FnMut(Range<u32>, Range<u32>)> Sink for T {
    type Out = ();

    fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
        self(before, after)
    }

    fn finish(self) -> Self::Out {}
}

impl Sink for () {
    type Out = ();
    fn process_change(&mut self, _before: Range<u32>, _after: Range<u32>) {}
    fn finish(self) -> Self::Out {}
}

/// A [`Sink`] which wraps a different sink
/// and counts the number of `removed` and `inserted` [tokens](crate::intern::Token).
pub struct Counter<T> {
    /// Total number of recorded inserted [`tokens`](crate::intern::Token).
    /// Computed by summing the lengths of the `after` subsequences pass to [`process_change`](crate::Sink::process_change).
    pub removals: u32,
    /// Total number of recorded inserted [`tokens`](crate::intern::Token).
    /// Computed by summing the lengths of the `after` subsequences pass to [`process_change`](crate::Sink::process_change).
    pub insertions: u32,
    /// The [`Sink`] for which the counter records [`tokens`](crate::intern::Token).
    /// All calls to [`process_change`](crate::Sink::process_change) are forwarded to the `sink` by the counter.
    /// After [`finish`](crate::Sink::finish) is called, this field contains the output returned by the [`finish`](crate::Sink::finish)
    /// method of the wrapped [`Sink`].
    pub wrapped: T,
}

impl<S: Sink> Counter<S> {
    pub fn new(sink: S) -> Self {
        Self {
            insertions: 0,
            removals: 0,
            wrapped: sink,
        }
    }
}

impl<S: Sink> Sink for Counter<S> {
    type Out = Counter<S::Out>;
    fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
        self.removals += before.end - before.start;
        self.insertions += after.end - after.start;
        self.wrapped.process_change(before, after)
    }

    fn finish(self) -> Self::Out {
        Counter {
            removals: self.removals,
            insertions: self.insertions,
            wrapped: self.wrapped.finish(),
        }
    }
}

impl<T> Counter<T> {
    pub fn total(&self) -> usize {
        self.insertions as usize + self.removals as usize
    }
}

impl Default for Counter<()> {
    fn default() -> Self {
        Counter::new(())
    }
}