Coverage Report

Created: 2025-06-02 07:01

/rust/registry/src/index.crates.io-6f17d22bba15001f/diff-0.1.13/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
/// A fragment of a computed diff.
2
#[derive(Clone, Debug, PartialEq)]
3
pub enum Result<T> {
4
    /// An element that only exists in the left input.
5
    Left(T),
6
    /// Elements that exist in both inputs.
7
    Both(T, T),
8
    /// An element that only exists in the right input.
9
    Right(T),
10
}
11
12
/// Computes the diff between two slices.
13
0
pub fn slice<'a, T: PartialEq>(left: &'a [T], right: &'a [T]) -> Vec<Result<&'a T>> {
14
0
    do_diff(left, right, |t| t)
15
0
}
16
17
/// Computes the diff between the lines of two strings.
18
0
pub fn lines<'a>(left: &'a str, right: &'a str) -> Vec<Result<&'a str>> {
19
0
    let mut diff = do_diff(
20
0
        &left.lines().collect::<Vec<_>>(),
21
0
        &right.lines().collect::<Vec<_>>(),
22
0
        |str| *str,
23
0
    );
24
0
    // str::lines() does not yield an empty str at the end if the str ends with
25
0
    // '\n'. We handle this special case by inserting one last diff item,
26
0
    // depending on whether the left string ends with '\n', or the right one,
27
0
    // or both.
28
0
    match (
29
0
        left.as_bytes().last().cloned(),
30
0
        right.as_bytes().last().cloned(),
31
    ) {
32
        (Some(b'\n'), Some(b'\n')) => {
33
0
            diff.push(Result::Both(&left[left.len()..], &right[right.len()..]))
34
        }
35
0
        (Some(b'\n'), _) => diff.push(Result::Left(&left[left.len()..])),
36
0
        (_, Some(b'\n')) => diff.push(Result::Right(&right[right.len()..])),
37
0
        _ => {}
38
    }
39
0
    diff
40
0
}
41
42
/// Computes the diff between the chars of two strings.
43
0
pub fn chars<'a>(left: &'a str, right: &'a str) -> Vec<Result<char>> {
44
0
    do_diff(
45
0
        &left.chars().collect::<Vec<_>>(),
46
0
        &right.chars().collect::<Vec<_>>(),
47
0
        |char| *char,
48
0
    )
49
0
}
50
51
0
fn do_diff<'a, T, F, U>(left: &'a [T], right: &'a [T], mapper: F) -> Vec<Result<U>>
52
0
where
53
0
    T: PartialEq,
54
0
    F: Fn(&'a T) -> U,
55
0
{
56
0
    let leading_equals = left
57
0
        .iter()
58
0
        .zip(right.iter())
59
0
        .take_while(|(l, r)| l == r)
Unexecuted instantiation: diff::do_diff::<&str, diff::lines::{closure#0}, &str>::{closure#0}
Unexecuted instantiation: diff::do_diff::<char, diff::chars::{closure#0}, char>::{closure#0}
60
0
        .count();
61
0
    let trailing_equals = left[leading_equals..]
62
0
        .iter()
63
0
        .rev()
64
0
        .zip(right[leading_equals..].iter().rev())
65
0
        .take_while(|(l, r)| l == r)
Unexecuted instantiation: diff::do_diff::<&str, diff::lines::{closure#0}, &str>::{closure#1}
Unexecuted instantiation: diff::do_diff::<char, diff::chars::{closure#0}, char>::{closure#1}
66
0
        .count();
67
68
0
    let table: Vec2<u32> = {
69
0
        let left_diff_size = left.len() - leading_equals - trailing_equals;
70
0
        let right_diff_size = right.len() - leading_equals - trailing_equals;
71
0
72
0
        let mut table = Vec2::new(0, [left_diff_size + 1, right_diff_size + 1]);
73
0
74
0
        let left_skip = &left[leading_equals..left.len() - trailing_equals];
75
0
        let right_skip = &right[leading_equals..right.len() - trailing_equals];
76
77
0
        for (i, l) in left_skip.iter().enumerate() {
78
0
            for (j, r) in right_skip.iter().enumerate() {
79
0
                table.set(
80
0
                    [i + 1, j + 1],
81
0
                    if l == r {
82
0
                        table.get([i, j]) + 1
83
                    } else {
84
0
                        *table.get([i, j + 1]).max(table.get([i + 1, j]))
85
                    },
86
                );
87
            }
88
        }
89
90
0
        table
91
0
    };
92
0
93
0
    let mut diff = Vec::with_capacity(left.len().max(right.len()));
94
0
95
0
    diff.extend(
96
0
        left[..leading_equals]
97
0
            .iter()
98
0
            .zip(&right[..leading_equals])
99
0
            .map(|(l, r)| Result::Both(mapper(l), mapper(r))),
Unexecuted instantiation: diff::do_diff::<&str, diff::lines::{closure#0}, &str>::{closure#2}
Unexecuted instantiation: diff::do_diff::<char, diff::chars::{closure#0}, char>::{closure#2}
100
0
    );
101
0
102
0
    {
103
0
        let start = diff.len();
104
0
        let mut i = table.len[0] - 1;
105
0
        let mut j = table.len[1] - 1;
106
0
        let left = &left[leading_equals..];
107
0
        let right = &right[leading_equals..];
108
109
        loop {
110
0
            if j > 0 && (i == 0 || table.get([i, j]) == table.get([i, j - 1])) {
111
0
                j -= 1;
112
0
                diff.push(Result::Right(mapper(&right[j])));
113
0
            } else if i > 0 && (j == 0 || table.get([i, j]) == table.get([i - 1, j])) {
114
0
                i -= 1;
115
0
                diff.push(Result::Left(mapper(&left[i])));
116
0
            } else if i > 0 && j > 0 {
117
0
                i -= 1;
118
0
                j -= 1;
119
0
                diff.push(Result::Both(mapper(&left[i]), mapper(&right[j])));
120
0
            } else {
121
0
                break;
122
0
            }
123
0
        }
124
0
        diff[start..].reverse();
125
0
    }
126
0
127
0
    diff.extend(
128
0
        left[left.len() - trailing_equals..]
129
0
            .iter()
130
0
            .zip(&right[right.len() - trailing_equals..])
131
0
            .map(|(l, r)| Result::Both(mapper(l), mapper(r))),
Unexecuted instantiation: diff::do_diff::<&str, diff::lines::{closure#0}, &str>::{closure#3}
Unexecuted instantiation: diff::do_diff::<char, diff::chars::{closure#0}, char>::{closure#3}
132
0
    );
133
0
134
0
    diff
135
0
}
Unexecuted instantiation: diff::do_diff::<&str, diff::lines::{closure#0}, &str>
Unexecuted instantiation: diff::do_diff::<char, diff::chars::{closure#0}, char>
136
137
struct Vec2<T> {
138
    len: [usize; 2],
139
    data: Vec<T>,
140
}
141
142
impl<T> Vec2<T> {
143
    #[inline]
144
0
    fn new(value: T, len: [usize; 2]) -> Self
145
0
    where
146
0
        T: Clone,
147
0
    {
148
0
        Vec2 {
149
0
            len,
150
0
            data: vec![value; len[0] * len[1]],
151
0
        }
152
0
    }
153
154
    #[inline]
155
0
    fn get(&self, index: [usize; 2]) -> &T {
156
0
        debug_assert!(index[0] < self.len[0]);
157
0
        debug_assert!(index[1] < self.len[1]);
158
0
        &self.data[index[0] * self.len[1] + index[1]]
159
0
    }
160
161
    #[inline]
162
0
    fn set(&mut self, index: [usize; 2], value: T) {
163
0
        debug_assert!(index[0] < self.len[0]);
164
0
        debug_assert!(index[1] < self.len[1]);
165
0
        self.data[index[0] * self.len[1] + index[1]] = value;
166
0
    }
167
}