blob: 190a96ef7f34e23a27baf2ac95a2524e1918ad6d [file] [log] [blame] [edit]
pub use self::r#impl::Diff;
pub enum Render<'a> {
Common(&'a str),
Unique(&'a str),
}
#[cfg(all(feature = "diff", not(windows)))]
mod r#impl {
use super::Render;
use dissimilar::Chunk;
use std::cmp;
use std::panic;
pub struct Diff<'a> {
expected: &'a str,
actual: &'a str,
diff: Vec<Chunk<'a>>,
}
impl<'a> Diff<'a> {
pub fn compute(expected: &'a str, actual: &'a str) -> Option<Self> {
if expected.len() + actual.len() > 2048 {
// We don't yet trust the dissimilar crate to work well on large
// inputs.
return None;
}
// Nor on non-ascii inputs.
let diff = panic::catch_unwind(|| dissimilar::diff(expected, actual)).ok()?;
let mut common_len = 0;
for chunk in &diff {
if let Chunk::Equal(common) = chunk {
common_len += common.len();
}
}
let bigger_len = cmp::max(expected.len(), actual.len());
let worth_printing = 5 * common_len >= 4 * bigger_len;
if !worth_printing {
return None;
}
Some(Diff {
expected,
actual,
diff,
})
}
pub fn iter<'i>(&'i self, input: &str) -> impl Iterator<Item = Render<'a>> + 'i {
let expected = input == self.expected;
let actual = input == self.actual;
self.diff.iter().filter_map(move |chunk| match chunk {
Chunk::Equal(common) => Some(Render::Common(common)),
Chunk::Delete(unique) if expected => Some(Render::Unique(unique)),
Chunk::Insert(unique) if actual => Some(Render::Unique(unique)),
_ => None,
})
}
}
}
#[cfg(any(not(feature = "diff"), windows))]
mod r#impl {
use super::Render;
pub enum Diff {}
impl Diff {
pub fn compute(_expected: &str, _actual: &str) -> Option<Self> {
None
}
pub fn iter(&self, _input: &str) -> Box<dyn Iterator<Item = Render>> {
let _ = Render::Common;
let _ = Render::Unique;
match *self {}
}
}
}