1use ahash::HashMap;
2use ahash::HashSet;
3use serde::Deserialize;
4use serde::Serialize;
5
6use mago_database::file::FileId;
7
8use crate::symbol::SymbolIdentifier;
9
10pub type DiffHunk = (usize, usize, isize, isize);
18
19pub type DeletionRange = (usize, usize);
25
26#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub struct CodebaseDiff {
34 keep: HashSet<SymbolIdentifier>,
38
39 changed: HashSet<SymbolIdentifier>,
43
44 diff_map: HashMap<FileId, Vec<DiffHunk>>,
47
48 deletion_ranges_map: HashMap<FileId, Vec<DeletionRange>>,
51}
52
53impl CodebaseDiff {
54 #[inline]
55 #[must_use]
56 pub fn new() -> Self {
57 Self::default()
58 }
59
60 #[inline]
62 pub fn extend(&mut self, other: Self) {
63 self.keep.extend(other.keep);
64 self.changed.extend(other.changed);
65 for (source, diffs) in other.diff_map {
66 self.diff_map.entry(source).or_default().extend(diffs);
67 }
68 for (source, ranges) in other.deletion_ranges_map {
69 self.deletion_ranges_map.entry(source).or_default().extend(ranges);
70 }
71 }
72
73 #[inline]
75 #[must_use]
76 pub fn get_keep(&self) -> &HashSet<SymbolIdentifier> {
77 &self.keep
78 }
79
80 #[inline]
82 #[must_use]
83 pub fn get_changed(&self) -> &HashSet<SymbolIdentifier> {
84 &self.changed
85 }
86
87 #[inline]
89 #[must_use]
90 pub fn get_diff_map(&self) -> &HashMap<FileId, Vec<DiffHunk>> {
91 &self.diff_map
92 }
93
94 #[inline]
96 #[must_use]
97 pub fn get_deletion_ranges_map(&self) -> &HashMap<FileId, Vec<DeletionRange>> {
98 &self.deletion_ranges_map
99 }
100
101 #[inline]
103 pub fn set_keep(&mut self, keep_set: impl IntoIterator<Item = SymbolIdentifier>) {
104 self.keep = keep_set.into_iter().collect();
105 }
106
107 #[inline]
109 pub fn with_keep(mut self, keep_set: impl IntoIterator<Item = SymbolIdentifier>) -> Self {
110 self.set_keep(keep_set);
111 self
112 }
113
114 #[inline]
116 pub fn add_keep_entry(&mut self, entry: SymbolIdentifier) -> bool {
117 self.keep.insert(entry)
118 }
119
120 #[inline]
122 #[must_use]
123 pub fn with_added_keep_entry(mut self, entry: SymbolIdentifier) -> Self {
124 self.add_keep_entry(entry);
125 self
126 }
127
128 #[inline]
130 pub fn add_keep_entries(&mut self, entries: impl IntoIterator<Item = SymbolIdentifier>) {
131 self.keep.extend(entries);
132 }
133
134 #[inline]
136 pub fn with_added_keep_entries(mut self, entries: impl IntoIterator<Item = SymbolIdentifier>) -> Self {
137 self.add_keep_entries(entries);
138 self
139 }
140
141 #[inline]
143 pub fn unset_keep(&mut self) {
144 self.keep.clear();
145 }
146
147 #[inline]
149 #[must_use]
150 pub fn without_keep(mut self) -> Self {
151 self.unset_keep();
152 self
153 }
154
155 #[inline]
157 pub fn set_changed(&mut self, change_set: impl IntoIterator<Item = SymbolIdentifier>) {
158 self.changed = change_set.into_iter().collect();
159 }
160
161 #[inline]
163 pub fn with_changed(mut self, change_set: impl IntoIterator<Item = SymbolIdentifier>) -> Self {
164 self.set_changed(change_set);
165 self
166 }
167
168 #[inline]
170 pub fn add_changed_entry(&mut self, entry: SymbolIdentifier) -> bool {
171 self.changed.insert(entry)
172 }
173
174 #[inline]
176 #[must_use]
177 pub fn contains_changed_entry(&self, entry: &SymbolIdentifier) -> bool {
178 self.changed.contains(entry)
179 }
180
181 #[inline]
183 #[must_use]
184 pub fn with_added_changed_entry(mut self, entry: SymbolIdentifier) -> Self {
185 self.add_changed_entry(entry);
186 self
187 }
188
189 #[inline]
191 pub fn add_changed_entries(&mut self, entries: impl IntoIterator<Item = SymbolIdentifier>) {
192 self.changed.extend(entries);
193 }
194
195 #[inline]
197 pub fn with_added_changed_entries(mut self, entries: impl IntoIterator<Item = SymbolIdentifier>) -> Self {
198 self.add_changed_entries(entries);
199 self
200 }
201
202 #[inline]
204 pub fn unset_changed(&mut self) {
205 self.changed.clear();
206 }
207
208 #[inline]
210 #[must_use]
211 pub fn without_changed(mut self) -> Self {
212 self.unset_changed();
213 self
214 }
215
216 #[inline]
218 pub fn set_diff_map(&mut self, map: HashMap<FileId, Vec<DiffHunk>>) {
219 self.diff_map = map;
220 }
221
222 #[inline]
224 #[must_use]
225 pub fn with_diff_map(mut self, map: HashMap<FileId, Vec<DiffHunk>>) -> Self {
226 self.set_diff_map(map);
227 self
228 }
229
230 #[inline]
232 pub fn add_diff_map_entry(&mut self, source: FileId, diffs: Vec<DiffHunk>) -> Option<Vec<DiffHunk>> {
233 self.diff_map.insert(source, diffs)
234 }
235
236 #[inline]
238 #[must_use]
239 pub fn with_added_diff_map_entry(mut self, source: FileId, diffs: Vec<DiffHunk>) -> Self {
240 self.add_diff_map_entry(source, diffs);
241 self
242 }
243
244 #[inline]
246 pub fn add_diffs_for_source(&mut self, source: FileId, diffs: impl IntoIterator<Item = DiffHunk>) {
247 self.diff_map.entry(source).or_default().extend(diffs);
248 }
249
250 #[inline]
252 pub fn with_added_diffs_for_source(mut self, source: FileId, diffs: impl IntoIterator<Item = DiffHunk>) -> Self {
253 self.add_diffs_for_source(source, diffs);
254 self
255 }
256
257 #[inline]
259 pub fn unset_diff_map(&mut self) {
260 self.diff_map.clear();
261 }
262
263 #[inline]
265 #[must_use]
266 pub fn without_diff_map(mut self) -> Self {
267 self.unset_diff_map();
268 self
269 }
270
271 #[inline]
273 pub fn set_deletion_ranges_map(&mut self, map: HashMap<FileId, Vec<DeletionRange>>) {
274 self.deletion_ranges_map = map;
275 }
276
277 #[inline]
279 #[must_use]
280 pub fn with_deletion_ranges_map(mut self, map: HashMap<FileId, Vec<DeletionRange>>) -> Self {
281 self.set_deletion_ranges_map(map);
282 self
283 }
284
285 #[inline]
287 pub fn add_deletion_ranges_entry(
288 &mut self,
289 source: FileId,
290 ranges: Vec<DeletionRange>,
291 ) -> Option<Vec<DeletionRange>> {
292 self.deletion_ranges_map.insert(source, ranges)
293 }
294
295 #[inline]
297 #[must_use]
298 pub fn with_added_deletion_ranges_entry(mut self, file: FileId, ranges: Vec<DeletionRange>) -> Self {
299 self.add_deletion_ranges_entry(file, ranges);
300 self
301 }
302
303 #[inline]
305 pub fn add_deletion_ranges_for_source(&mut self, file: FileId, ranges: impl IntoIterator<Item = (usize, usize)>) {
306 self.deletion_ranges_map.entry(file).or_default().extend(ranges);
307 }
308
309 #[inline]
311 pub fn with_added_deletion_ranges_for_source(
312 mut self,
313 file: FileId,
314 ranges: impl IntoIterator<Item = (usize, usize)>,
315 ) -> Self {
316 self.add_deletion_ranges_for_source(file, ranges);
317 self
318 }
319
320 #[inline]
322 pub fn unset_deletion_ranges_map(&mut self) {
323 self.deletion_ranges_map.clear();
324 }
325
326 #[inline]
328 #[must_use]
329 pub fn without_deletion_ranges_map(mut self) -> Self {
330 self.unset_deletion_ranges_map();
331 self
332 }
333}