1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
14#[serde(rename_all = "kebab-case")]
15pub enum NearDupScope {
16 #[default]
18 Module,
19 Lang,
21 Global,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct NearDupParams {
28 pub scope: NearDupScope,
29 pub threshold: f64,
30 pub max_files: usize,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub max_pairs: Option<usize>,
34 #[serde(default, skip_serializing_if = "Option::is_none")]
36 pub max_file_bytes: Option<u64>,
37 #[serde(default, skip_serializing_if = "Option::is_none")]
39 pub selection_method: Option<String>,
40 #[serde(default, skip_serializing_if = "Option::is_none")]
42 pub algorithm: Option<NearDupAlgorithm>,
43 #[serde(default, skip_serializing_if = "Vec::is_empty")]
45 pub exclude_patterns: Vec<String>,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
50pub struct NearDupAlgorithm {
51 pub k_gram_size: usize,
53 pub window_size: usize,
55 pub max_postings: usize,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct NearDuplicateReport {
62 pub params: NearDupParams,
63 pub pairs: Vec<NearDupPairRow>,
64 pub files_analyzed: usize,
65 pub files_skipped: usize,
66 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub eligible_files: Option<usize>,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
71 pub clusters: Option<Vec<NearDupCluster>>,
72 #[serde(default)]
75 pub truncated: bool,
76 #[serde(default, skip_serializing_if = "Option::is_none")]
78 pub excluded_by_pattern: Option<usize>,
79 #[serde(default, skip_serializing_if = "Option::is_none")]
81 pub stats: Option<NearDupStats>,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct NearDupCluster {
87 pub files: Vec<String>,
89 pub max_similarity: f64,
91 pub representative: String,
93 pub pair_count: usize,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99pub struct NearDupStats {
100 pub fingerprinting_ms: u64,
102 pub pairing_ms: u64,
104 pub bytes_processed: u64,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct NearDupPairRow {
111 pub left: String,
112 pub right: String,
113 pub similarity: f64,
114 pub shared_fingerprints: usize,
115 pub left_fingerprints: usize,
116 pub right_fingerprints: usize,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct DuplicateReport {
125 pub groups: Vec<DuplicateGroup>,
126 pub wasted_bytes: u64,
127 pub strategy: String,
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub density: Option<DuplicationDensityReport>,
131 #[serde(default, skip_serializing_if = "Option::is_none")]
133 pub near: Option<NearDuplicateReport>,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct DuplicateGroup {
138 pub hash: String,
139 pub bytes: u64,
140 pub files: Vec<String>,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct DuplicationDensityReport {
145 pub duplicate_groups: usize,
146 pub duplicate_files: usize,
147 pub duplicated_bytes: u64,
148 pub wasted_bytes: u64,
149 pub wasted_pct_of_codebase: f64,
150 pub by_module: Vec<ModuleDuplicationDensityRow>,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct ModuleDuplicationDensityRow {
155 pub module: String,
156 pub duplicate_files: usize,
157 pub wasted_files: usize,
158 pub duplicated_bytes: u64,
159 pub wasted_bytes: u64,
160 pub module_bytes: u64,
161 pub density: f64,
162}