similar 1.3.0

A diff library for Rust
Documentation
use std::fmt;

use console::{style, Style};
use similar::{Algorithm, ChangeTag, TextDiff};

pub struct Diff {
    left: String,
    right: String,
}

fn to_debug<D: fmt::Debug>(d: &D) -> String {
    use fmt::Write;
    let mut buf = String::new();
    buf.write_fmt(format_args!("{:#?}", d))
        .expect("a Debug implementation returned an error unexpectedly");
    buf
}

impl Diff {
    pub fn from_debug<Left: fmt::Debug, Right: fmt::Debug>(left: &Left, right: &Right) -> Diff {
        let left = to_debug(left).into();
        let right = to_debug(right).into();
        Diff { left, right }
    }
}

impl fmt::Display for Diff {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.left == self.right {
            writeln!(
                f,
                "{}: {}",
                style("Invisible differences").bold(),
                "the two values are the same in string form."
            )?;
            return Ok(());
        }

        let diff = TextDiff::configure()
            .algorithm(Algorithm::Patience)
            .diff_lines(&self.left, &self.right);
        writeln!(
            f,
            "  {} ({}|{}):",
            style("Differences").bold(),
            style("<left").red(),
            style(">right").green(),
        )?;
        for (idx, group) in diff.grouped_ops(4).into_iter().enumerate() {
            if idx > 0 {
                writeln!(f, "  ~~~")?;
            }
            for op in group {
                for change in diff.iter_inline_changes(&op) {
                    let (marker, style) = match change.tag() {
                        ChangeTag::Delete => ('<', Style::new().red()),
                        ChangeTag::Insert => ('>', Style::new().green()),
                        ChangeTag::Equal => (' ', Style::new().dim()),
                    };
                    write!(f, "   {}", style.apply_to(marker).dim().bold())?;
                    #[cfg(feature = "inline")]
                    {
                        for &(emphasized, value) in change.values() {
                            if emphasized {
                                write!(f, "{}", style.clone().underlined().bold().apply_to(value))?;
                            } else {
                                write!(f, "{}", style.apply_to(value))?;
                            }
                        }
                    }
                    #[cfg(not(feature = "inline"))]
                    {
                        write!(f, "{}", style.apply_to(change.value()))?;
                    }
                    if change.missing_newline() {
                        writeln!(f)?;
                    }
                }
            }
        }
        Ok(())
    }
}

#[macro_export]
macro_rules! assert_eq {
    ($left:expr, $right:expr $(,)?) => ({
        match (&($left), &($right)) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    panic!("assertion failed: `(left == right)`'\
                           \n  left: `{:?}`\
                           \n right: `{:?}`\
                           \n\n{}\n",
                           &*left_val,
                           &*right_val,
                           $crate::Diff::from_debug(&*left_val, &*right_val));
                }
            }
        }
    });
    ($left:expr, $right:expr, $($arg:tt)*) => ({
        match (&($left), &($right)) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    panic!("assertion failed: `(left == right)`: {}'\
                           \n  left: `{:?}`\
                           \n right: `{:?}`\
                           \n\n{}\n",
                           format_args!($($arg)*),
                           &*left_val,
                           &*right_val,
                           $crate::Diff::from_debug(&*left_val, &*right_val));
                }
            }
        }
    });
}

fn main() {
    let vec1: Vec<_> = (1..100).collect();
    let mut vec2 = vec1.clone();
    vec2[52] = 2;
    vec2[12] = 33;
    assert_eq!(vec1, vec2);
}