difference/
merge.rs

1use Difference;
2
3// merges the changes from two strings, given a common substring
4pub fn merge(orig: &str, edit: &str, common: &str, split: &str) -> Vec<Difference> {
5    let mut ret = Vec::new();
6
7    let mut l = orig.split(split).peekable();
8    let mut r = edit.split(split).peekable();
9    let mut c = common.split(split).peekable();
10
11    // Turn empty strings into [], not [""]
12    if orig == "" {
13        l.next();
14    }
15    if edit == "" {
16        r.next();
17    }
18    if common == "" {
19        c.next();
20    }
21
22    while l.peek().is_some() || r.peek().is_some() {
23        let mut same = Vec::new();
24        while l.peek().is_some() && l.peek() == c.peek() && r.peek() == c.peek() {
25            same.push(l.next().unwrap());
26            r.next();
27            c.next();
28        }
29        if !same.is_empty() {
30            let joined = same.join(split);
31            if split != "" || joined != "" {
32                ret.push(Difference::Same(joined));
33            }
34        }
35
36        let mut rem = Vec::new();
37        while l.peek().is_some() && l.peek() != c.peek() {
38            rem.push(l.next().unwrap());
39        }
40        if !rem.is_empty() {
41            ret.push(Difference::Rem(rem.join(split)));
42        }
43
44        let mut add = Vec::new();
45        while r.peek().is_some() && r.peek() != c.peek() {
46            add.push(r.next().unwrap());
47        }
48        if !add.is_empty() {
49            ret.push(Difference::Add(add.join(split)));
50        }
51    }
52
53    ret
54}
55
56
57#[test]
58fn test_merge() {
59    assert_eq!(
60        merge("testa", "tost", "tst", ""),
61        vec![
62            Difference::Same("t".to_string()),
63            Difference::Rem("e".to_string()),
64            Difference::Add("o".to_string()),
65            Difference::Same("st".to_string()),
66            Difference::Rem("a".to_string()),
67        ]
68    );
69
70    assert_eq!(
71        merge("", "a", "", ""),
72        vec![Difference::Add("a".to_string())]
73    );
74
75    assert_eq!(
76        merge("a\nb", "a\n\nb", "a\nb", "\n"),
77        vec![
78            Difference::Same("a".to_string()),
79            Difference::Add("".to_string()),
80            Difference::Same("b".to_string()),
81        ]
82    );
83
84    assert_eq!(
85        merge("a\n", "c\n", "\n", "\n"),
86        vec![
87            Difference::Rem("a".to_string()),
88            Difference::Add("c".to_string()),
89            Difference::Same("".to_string()),
90        ]
91    );
92}