use serde::Serialize;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct FileDiff {
pub path: String,
pub nodes: Vec<DiffNode>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub enum DiffKind {
Added,
Removed,
Renamed,
Modified,
Unchanged,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct DiffNode {
pub name: String,
pub kind: DiffKind,
#[serde(skip_serializing_if = "Option::is_none")]
pub old_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub param_cases: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub old_param_cases: Option<usize>,
pub children: Vec<DiffNode>,
}
impl DiffNode {
pub fn has_changes(&self) -> bool {
if self.kind != DiffKind::Unchanged {
return true;
}
self.children.iter().any(DiffNode::has_changes)
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct Stats {
pub added: usize,
pub removed: usize,
pub renamed: usize,
pub modified: usize,
}
impl Stats {
pub fn from_file_diffs(file_diffs: &[FileDiff]) -> Self {
let mut stats = Stats::default();
for fd in file_diffs {
stats.count_nodes(&fd.nodes);
}
stats
}
fn count_nodes(&mut self, nodes: &[DiffNode]) {
for node in nodes {
let is_leaf = node.children.is_empty();
match node.kind {
DiffKind::Added if is_leaf => self.added += 1,
DiffKind::Removed if is_leaf => self.removed += 1,
DiffKind::Renamed => self.renamed += 1,
DiffKind::Modified
| DiffKind::Added
| DiffKind::Removed
| DiffKind::Unchanged => {}
}
self.count_nodes(&node.children);
}
}
pub fn is_empty(&self) -> bool {
self.added == 0 && self.removed == 0 && self.renamed == 0 && self.modified == 0
}
}