#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LineKind {
Context,
Add,
Del,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Line {
pub kind: LineKind,
pub text: Vec<u8>,
pub no_newline: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Hunk {
pub old_start: u32,
pub old_lines: u32,
pub new_start: u32,
pub new_lines: u32,
pub section: Vec<u8>,
pub lines: Vec<Line>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FileContent {
Text(Vec<Hunk>),
Binary(Vec<Vec<u8>>),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FileDiff {
pub headers: Vec<Vec<u8>>,
pub old_path: Option<Vec<u8>>,
pub new_path: Option<Vec<u8>>,
pub content: FileContent,
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct Patch {
pub files: Vec<FileDiff>,
}
impl FileDiff {
pub fn display_path(&self) -> String {
self.new_path
.as_deref()
.or(self.old_path.as_deref())
.map(|b| String::from_utf8_lossy(b).into_owned())
.unwrap_or_default()
}
}
pub(crate) fn count_kinds(lines: &[Line]) -> (u32, u32, u32) {
let mut ctx = 0;
let mut add = 0;
let mut del = 0;
for l in lines {
match l.kind {
LineKind::Context => ctx += 1,
LineKind::Add => add += 1,
LineKind::Del => del += 1,
}
}
(ctx, add, del)
}
impl Hunk {
pub fn change_counts(&self) -> (u32, u32) {
let (_, add, del) = count_kinds(&self.lines);
(add, del)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn change_counts_counts_add_and_del() {
let h = Hunk {
old_start: 1,
old_lines: 2,
new_start: 1,
new_lines: 2,
section: Vec::new(),
lines: vec![
Line {
kind: LineKind::Context,
text: b"a".to_vec(),
no_newline: false,
},
Line {
kind: LineKind::Del,
text: b"b".to_vec(),
no_newline: false,
},
Line {
kind: LineKind::Add,
text: b"c".to_vec(),
no_newline: false,
},
],
};
assert_eq!(h.change_counts(), (1, 1));
}
}