1 | pub use self::r#impl::Diff; |
2 | |
3 | pub enum Render<'a> { |
4 | Common(&'a str), |
5 | Unique(&'a str), |
6 | } |
7 | |
8 | #[cfg (all(feature = "diff" , not(windows)))] |
9 | mod r#impl { |
10 | use super::Render; |
11 | use dissimilar::Chunk; |
12 | use std::cmp; |
13 | use std::panic; |
14 | |
15 | pub struct Diff<'a> { |
16 | expected: &'a str, |
17 | actual: &'a str, |
18 | diff: Vec<Chunk<'a>>, |
19 | } |
20 | |
21 | impl<'a> Diff<'a> { |
22 | pub fn compute(expected: &'a str, actual: &'a str) -> Option<Self> { |
23 | if expected.len() + actual.len() > 2048 { |
24 | // We don't yet trust the dissimilar crate to work well on large |
25 | // inputs. |
26 | return None; |
27 | } |
28 | |
29 | // Nor on non-ascii inputs. |
30 | let diff = panic::catch_unwind(|| dissimilar::diff(expected, actual)).ok()?; |
31 | |
32 | let mut common_len = 0; |
33 | for chunk in &diff { |
34 | if let Chunk::Equal(common) = chunk { |
35 | common_len += common.len(); |
36 | } |
37 | } |
38 | |
39 | let bigger_len = cmp::max(expected.len(), actual.len()); |
40 | let worth_printing = 5 * common_len >= 4 * bigger_len; |
41 | if !worth_printing { |
42 | return None; |
43 | } |
44 | |
45 | Some(Diff { |
46 | expected, |
47 | actual, |
48 | diff, |
49 | }) |
50 | } |
51 | |
52 | pub fn iter<'i>(&'i self, input: &str) -> impl Iterator<Item = Render<'a>> + 'i { |
53 | let expected = input == self.expected; |
54 | let actual = input == self.actual; |
55 | self.diff.iter().filter_map(move |chunk| match chunk { |
56 | Chunk::Equal(common) => Some(Render::Common(common)), |
57 | Chunk::Delete(unique) if expected => Some(Render::Unique(unique)), |
58 | Chunk::Insert(unique) if actual => Some(Render::Unique(unique)), |
59 | _ => None, |
60 | }) |
61 | } |
62 | } |
63 | } |
64 | |
65 | #[cfg (any(not(feature = "diff" ), windows))] |
66 | mod r#impl { |
67 | use super::Render; |
68 | |
69 | pub enum Diff {} |
70 | |
71 | impl Diff { |
72 | pub fn compute(_expected: &str, _actual: &str) -> Option<Self> { |
73 | None |
74 | } |
75 | |
76 | pub fn iter(&self, _input: &str) -> Box<dyn Iterator<Item = Render>> { |
77 | let _ = Render::Common; |
78 | let _ = Render::Unique; |
79 | match *self {} |
80 | } |
81 | } |
82 | } |
83 | |