use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "kebab-case")]
pub enum NearDupScope {
#[default]
Module,
Lang,
Global,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NearDupParams {
pub scope: NearDupScope,
pub threshold: f64,
pub max_files: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_pairs: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_file_bytes: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub selection_method: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub algorithm: Option<NearDupAlgorithm>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub exclude_patterns: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NearDupAlgorithm {
pub k_gram_size: usize,
pub window_size: usize,
pub max_postings: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NearDuplicateReport {
pub params: NearDupParams,
pub pairs: Vec<NearDupPairRow>,
pub files_analyzed: usize,
pub files_skipped: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub eligible_files: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub clusters: Option<Vec<NearDupCluster>>,
#[serde(default)]
pub truncated: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub excluded_by_pattern: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stats: Option<NearDupStats>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NearDupCluster {
pub files: Vec<String>,
pub max_similarity: f64,
pub representative: String,
pub pair_count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NearDupStats {
pub fingerprinting_ms: u64,
pub pairing_ms: u64,
pub bytes_processed: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NearDupPairRow {
pub left: String,
pub right: String,
pub similarity: f64,
pub shared_fingerprints: usize,
pub left_fingerprints: usize,
pub right_fingerprints: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DuplicateReport {
pub groups: Vec<DuplicateGroup>,
pub wasted_bytes: u64,
pub strategy: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub density: Option<DuplicationDensityReport>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub near: Option<NearDuplicateReport>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DuplicateGroup {
pub hash: String,
pub bytes: u64,
pub files: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DuplicationDensityReport {
pub duplicate_groups: usize,
pub duplicate_files: usize,
pub duplicated_bytes: u64,
pub wasted_bytes: u64,
pub wasted_pct_of_codebase: f64,
pub by_module: Vec<ModuleDuplicationDensityRow>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModuleDuplicationDensityRow {
pub module: String,
pub duplicate_files: usize,
pub wasted_files: usize,
pub duplicated_bytes: u64,
pub wasted_bytes: u64,
pub module_bytes: u64,
pub density: f64,
}