diffus/diffable_impls/
string.rs

1use crate::{
2    edit::{self, string},
3    lcs, Diffable,
4};
5
6impl<'a> Diffable<'a> for str {
7    type Diff = Vec<string::Edit>;
8
9    fn diff(&'a self, other: &'a Self) -> edit::Edit<Self> {
10        let s = lcs::lcs(
11            || self.chars(),
12            || other.chars(),
13            self.chars().count(),
14            other.chars().count(),
15        )
16        .map(Into::into)
17        .collect::<Vec<_>>();
18
19        if s.iter().all(string::Edit::is_copy) {
20            edit::Edit::Copy(self)
21        } else {
22            edit::Edit::Change(s)
23        }
24    }
25}
26
27impl<'a> Diffable<'a> for String {
28    type Diff = <str as Diffable<'a>>::Diff;
29
30    fn diff(&'a self, other: &'a Self) -> edit::Edit<Self> {
31        match self.as_str().diff(other.as_str()) {
32            edit::Edit::Change(diff) => edit::Edit::Change(diff),
33            edit::Edit::Copy(_) => edit::Edit::Copy(self),
34        }
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use crate::edit::{self, string};
41
42    #[test]
43    fn string() {
44        use super::Diffable;
45
46        let left = "XMJYAUZ".to_owned();
47        let right = "MZJAWXU".to_owned();
48
49        let diff = left.diff(&right);
50        if let edit::Edit::Change(diff) = diff {
51            assert_eq!(
52                diff.into_iter().collect::<Vec<_>>(),
53                vec![
54                    string::Edit::Remove('X'),
55                    string::Edit::Copy('M'),
56                    string::Edit::Insert('Z'),
57                    string::Edit::Copy('J'),
58                    string::Edit::Remove('Y'),
59                    string::Edit::Copy('A'),
60                    string::Edit::Insert('W'),
61                    string::Edit::Insert('X'),
62                    string::Edit::Copy('U'),
63                    string::Edit::Remove('Z')
64                ]
65            );
66        } else {
67            unreachable!()
68        }
69    }
70
71    #[test]
72    fn str() {
73        use super::Diffable;
74
75        let left = "XMJYAUZ";
76        let right = "MZJAWXU";
77
78        let diff = left.diff(&right);
79        if let edit::Edit::Change(diff) = diff {
80            assert_eq!(
81                diff.into_iter().collect::<Vec<_>>(),
82                vec![
83                    string::Edit::Remove('X'),
84                    string::Edit::Copy('M'),
85                    string::Edit::Insert('Z'),
86                    string::Edit::Copy('J'),
87                    string::Edit::Remove('Y'),
88                    string::Edit::Copy('A'),
89                    string::Edit::Insert('W'),
90                    string::Edit::Insert('X'),
91                    string::Edit::Copy('U'),
92                    string::Edit::Remove('Z')
93                ]
94            );
95        } else {
96            unreachable!()
97        }
98    }
99}