Coverage Report

Created: 2026-03-31 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/imara-diff-0.1.8/src/sink.rs
Line
Count
Source
1
use std::ops::Range;
2
3
/// Trait for processing the edit-scripts computed with [`diff`](crate::diff)
4
pub 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
0
    fn with_counter(self) -> Counter<Self> {
41
0
        Counter::new(self)
42
0
    }
43
}
44
45
impl<T: FnMut(Range<u32>, Range<u32>)> Sink for T {
46
    type Out = ();
47
48
0
    fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
49
0
        self(before, after)
50
0
    }
Unexecuted instantiation: <<imara_diff::histogram::Histogram>::run<gix_merge::blob::builtin_driver::text::utils::CollectHunks>::{closure#0} as imara_diff::sink::Sink>::process_change
Unexecuted instantiation: <_ as imara_diff::sink::Sink>::process_change
51
52
0
    fn finish(self) -> Self::Out {}
Unexecuted instantiation: <<imara_diff::histogram::Histogram>::run<gix_merge::blob::builtin_driver::text::utils::CollectHunks>::{closure#0} as imara_diff::sink::Sink>::finish
Unexecuted instantiation: <_ as imara_diff::sink::Sink>::finish
53
}
54
55
impl Sink for () {
56
    type Out = ();
57
0
    fn process_change(&mut self, _before: Range<u32>, _after: Range<u32>) {}
58
0
    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).
63
pub 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
77
impl<S: Sink> Counter<S> {
78
0
    pub fn new(sink: S) -> Self {
79
0
        Self {
80
0
            insertions: 0,
81
0
            removals: 0,
82
0
            wrapped: sink,
83
0
        }
84
0
    }
85
}
86
87
impl<S: Sink> Sink for Counter<S> {
88
    type Out = Counter<S::Out>;
89
0
    fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
90
0
        self.removals += before.end - before.start;
91
0
        self.insertions += after.end - after.start;
92
0
        self.wrapped.process_change(before, after)
93
0
    }
94
95
0
    fn finish(self) -> Self::Out {
96
0
        Counter {
97
0
            removals: self.removals,
98
0
            insertions: self.insertions,
99
0
            wrapped: self.wrapped.finish(),
100
0
        }
101
0
    }
102
}
103
104
impl<T> Counter<T> {
105
0
    pub fn total(&self) -> usize {
106
0
        self.insertions as usize + self.removals as usize
107
0
    }
108
}
109
110
impl Default for Counter<()> {
111
0
    fn default() -> Self {
112
0
        Counter::new(())
113
0
    }
114
}