1use crate::license_detection::position_set::PositionSet;
7
8pub enum SpanIter<'a> {
9 Range(std::ops::Range<usize>),
10 Slice(std::iter::Copied<std::slice::Iter<'a, usize>>),
11}
12
13impl<'a> Iterator for SpanIter<'a> {
14 type Item = usize;
15
16 fn next(&mut self) -> Option<Self::Item> {
17 match self {
18 SpanIter::Range(range) => range.next(),
19 SpanIter::Slice(iter) => iter.next(),
20 }
21 }
22
23 fn size_hint(&self) -> (usize, Option<usize>) {
24 match self {
25 SpanIter::Range(range) => range.size_hint(),
26 SpanIter::Slice(iter) => iter.size_hint(),
27 }
28 }
29}
30
31#[derive(Debug, Clone)]
32pub enum PositionSpan {
33 Range { start: usize, end: usize },
34 Discrete(Vec<usize>),
35}
36
37impl PartialEq for PositionSpan {
38 fn eq(&self, other: &Self) -> bool {
48 match (self, other) {
49 (
50 PositionSpan::Range { start: s1, end: e1 },
51 PositionSpan::Range { start: s2, end: e2 },
52 ) => s1 == s2 && e1 == e2,
53 (PositionSpan::Discrete(p1), PositionSpan::Discrete(p2)) => p1 == p2,
54 (PositionSpan::Range { start, end }, PositionSpan::Discrete(positions)) => {
55 let range_len = end.saturating_sub(*start);
56 if range_len != positions.len() {
57 return false;
58 }
59 if positions.is_empty() {
60 return true;
61 }
62 positions.iter().all(|&p| *start <= p && p < *end)
63 }
64 (PositionSpan::Discrete(_), PositionSpan::Range { .. }) => other == self,
65 }
66 }
67}
68
69impl PositionSpan {
70 pub fn range(start: usize, end: usize) -> Self {
71 Self::Range { start, end }
72 }
73
74 pub fn new(start: usize, end: usize) -> Self {
75 Self::range(start, end)
76 }
77
78 pub fn from_positions(positions: impl IntoIterator<Item = usize>) -> Self {
79 let mut iter = positions.into_iter();
80 let Some(first) = iter.next() else {
81 return Self::empty();
82 };
83
84 let mut positions = vec![first];
85 positions.extend(iter);
86
87 if positions.len() == 1 {
88 return Self::Range {
89 start: positions[0],
90 end: positions[0] + 1,
91 };
92 }
93
94 positions.sort_unstable();
95 positions.dedup();
96
97 let is_contiguous = positions.windows(2).all(|w| w[1] == w[0] + 1);
98
99 if is_contiguous {
100 Self::Range {
101 start: positions[0],
102 end: positions[positions.len() - 1] + 1,
103 }
104 } else {
105 Self::Discrete(positions)
106 }
107 }
108
109 pub fn empty() -> Self {
110 Self::Range { start: 0, end: 0 }
111 }
112
113 pub fn iter(&self) -> SpanIter<'_> {
114 match self {
115 PositionSpan::Range { start, end } => SpanIter::Range(*start..*end),
116 PositionSpan::Discrete(positions) => SpanIter::Slice(positions.iter().copied()),
117 }
118 }
119
120 pub fn len(&self) -> usize {
121 match self {
122 PositionSpan::Range { start, end } => end.saturating_sub(*start),
123 PositionSpan::Discrete(positions) => positions.len(),
124 }
125 }
126
127 pub fn is_empty(&self) -> bool {
128 self.len() == 0
129 }
130
131 pub fn bounds(&self) -> (usize, usize) {
132 match self {
133 PositionSpan::Range { start, end } => (*start, *end),
134 PositionSpan::Discrete(positions) => {
135 if positions.is_empty() {
136 return (0, 0);
137 }
138 let min = positions.iter().copied().min().unwrap_or(0);
139 let max = positions.iter().copied().max().unwrap_or(0);
140 (min, max + 1)
141 }
142 }
143 }
144
145 pub fn contains(&self, pos: usize) -> bool {
146 match self {
147 PositionSpan::Range { start, end } => *start <= pos && pos < *end,
148 PositionSpan::Discrete(positions) => positions.binary_search(&pos).is_ok(),
149 }
150 }
151
152 pub fn overlaps_set(&self, set: &PositionSet) -> bool {
153 let (my_min, my_max) = self.bounds();
154 if self.is_empty() {
155 return false;
156 }
157 if !set.may_overlap_range(my_min, my_max) {
158 return false;
159 }
160 self.iter().any(|p| set.contains(p))
161 }
162
163 pub fn to_position_set(&self) -> PositionSet {
164 match self {
165 PositionSpan::Range { start, end } => (*start..*end).collect(),
166 PositionSpan::Discrete(positions) => positions.iter().copied().collect(),
167 }
168 }
169
170 pub fn to_vec(&self) -> Vec<usize> {
171 match self {
172 PositionSpan::Range { start, end } => (*start..*end).collect(),
173 PositionSpan::Discrete(positions) => positions.clone(),
174 }
175 }
176
177 pub fn is_contiguous(&self) -> bool {
180 match self {
181 PositionSpan::Range { .. } => true,
182 PositionSpan::Discrete(positions) => {
183 if positions.len() <= 1 {
184 return true;
185 }
186 positions.windows(2).all(|w| w[1] == w[0] + 1)
187 }
188 }
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 #[test]
197 fn test_range_creation() {
198 let span = PositionSpan::range(5, 10);
199 assert_eq!(span.len(), 5);
200 assert!(!span.is_empty());
201 assert_eq!(span.bounds(), (5, 10));
202 assert!(span.is_contiguous());
203 }
204
205 #[test]
206 fn test_new_backwards_compatible() {
207 let span = PositionSpan::new(3, 7);
208 assert_eq!(span.len(), 4);
209 assert_eq!(span.to_vec(), vec![3, 4, 5, 6]);
210 }
211
212 #[test]
213 fn test_empty() {
214 let span = PositionSpan::empty();
215 assert_eq!(span.len(), 0);
216 assert!(span.is_empty());
217 assert_eq!(span.bounds(), (0, 0));
218 }
219
220 #[test]
221 fn test_from_positions_empty() {
222 let span = PositionSpan::from_positions(vec![]);
223 assert!(span.is_empty());
224 }
225
226 #[test]
227 fn test_from_positions_single() {
228 let span = PositionSpan::from_positions(vec![5]);
229 assert_eq!(span.len(), 1);
230 assert!(span.is_contiguous());
231 assert!(span.contains(5));
232 }
233
234 #[test]
235 fn test_from_positions_contiguous() {
236 let span = PositionSpan::from_positions(vec![3, 4, 5]);
237 assert!(span.is_contiguous());
238 assert_eq!(span.len(), 3);
239 assert_eq!(span.bounds(), (3, 6));
240 }
241
242 #[test]
243 fn test_from_positions_non_contiguous() {
244 let span = PositionSpan::from_positions(vec![1, 3, 5]);
245 assert!(!span.is_contiguous());
246 assert_eq!(span.len(), 3);
247 assert_eq!(span.bounds(), (1, 6));
248 }
249
250 #[test]
251 fn test_from_positions_unsorted_with_duplicates() {
252 let span = PositionSpan::from_positions(vec![5, 3, 4, 3, 5]);
253 assert!(span.is_contiguous());
254 assert_eq!(span.to_vec(), vec![3, 4, 5]);
255 }
256
257 #[test]
258 fn test_contains_range() {
259 let span = PositionSpan::range(5, 10);
260 assert!(!span.contains(4));
261 assert!(span.contains(5));
262 assert!(span.contains(7));
263 assert!(span.contains(9));
264 assert!(!span.contains(10));
265 }
266
267 #[test]
268 fn test_contains_discrete() {
269 let span = PositionSpan::from_positions(vec![1, 3, 5]);
270 assert!(span.contains(1));
271 assert!(!span.contains(2));
272 assert!(span.contains(3));
273 assert!(!span.contains(4));
274 assert!(span.contains(5));
275 }
276
277 #[test]
278 fn test_iter_range() {
279 let span = PositionSpan::range(2, 5);
280 let positions: Vec<_> = span.iter().collect();
281 assert_eq!(positions, vec![2, 3, 4]);
282 }
283
284 #[test]
285 fn test_iter_discrete() {
286 let span = PositionSpan::from_positions(vec![1, 3, 5]);
287 let positions: Vec<_> = span.iter().collect();
288 assert_eq!(positions, vec![1, 3, 5]);
289 }
290
291 #[test]
292 fn test_to_vec_range() {
293 let span = PositionSpan::range(1, 4);
294 assert_eq!(span.to_vec(), vec![1, 2, 3]);
295 }
296
297 #[test]
298 fn test_to_vec_discrete() {
299 let span = PositionSpan::from_positions(vec![2, 4, 6]);
300 assert_eq!(span.to_vec(), vec![2, 4, 6]);
301 }
302
303 #[test]
304 fn test_to_position_set() {
305 let span = PositionSpan::range(1, 4);
306 let set = span.to_position_set();
307 assert_eq!(set.len(), 3);
308 assert!(set.contains(1));
309 assert!(set.contains(2));
310 assert!(set.contains(3));
311 }
312
313 #[test]
314 fn test_is_contiguous_discrete_single() {
315 let span = PositionSpan::from_positions(vec![5]);
316 assert!(span.is_contiguous());
317 }
318
319 #[test]
320 fn test_is_contiguous_discrete_gap() {
321 let span = PositionSpan::from_positions(vec![1, 2, 4]);
322 assert!(!span.is_contiguous());
323 }
324
325 #[test]
332 fn test_eq_range_range_both_empty() {
333 let a = PositionSpan::range(0, 0);
334 let b = PositionSpan::range(0, 0);
335 assert_eq!(a, b);
336 }
337
338 #[test]
339 fn test_eq_range_range_one_empty() {
340 let a = PositionSpan::range(0, 0);
341 let b = PositionSpan::range(0, 3);
342 assert_ne!(a, b);
343 }
344
345 #[test]
346 fn test_eq_range_range_equal() {
347 let a = PositionSpan::range(2, 5);
348 let b = PositionSpan::range(2, 5);
349 assert_eq!(a, b);
350 }
351
352 #[test]
353 fn test_eq_range_range_disjoint() {
354 let a = PositionSpan::range(0, 3);
355 let b = PositionSpan::range(5, 8);
356 assert_ne!(a, b);
357 }
358
359 #[test]
360 fn test_eq_range_range_overlapping() {
361 let a = PositionSpan::range(0, 5);
362 let b = PositionSpan::range(3, 8);
363 assert_ne!(a, b);
364 }
365
366 #[test]
369 fn test_eq_discrete_discrete_both_empty() {
370 let a = PositionSpan::Discrete(vec![]);
371 let b = PositionSpan::Discrete(vec![]);
372 assert_eq!(a, b);
373 }
374
375 #[test]
376 fn test_eq_discrete_discrete_one_empty() {
377 let a = PositionSpan::Discrete(vec![]);
378 let b = PositionSpan::Discrete(vec![0, 1, 2]);
379 assert_ne!(a, b);
380 }
381
382 #[test]
383 fn test_eq_discrete_discrete_equal() {
384 let a = PositionSpan::Discrete(vec![0, 1, 2]);
385 let b = PositionSpan::Discrete(vec![0, 1, 2]);
386 assert_eq!(a, b);
387 }
388
389 #[test]
390 fn test_eq_discrete_discrete_disjoint() {
391 let a = PositionSpan::Discrete(vec![0, 1, 2]);
392 let b = PositionSpan::Discrete(vec![5, 6, 7]);
393 assert_ne!(a, b);
394 }
395
396 #[test]
397 fn test_eq_discrete_discrete_overlapping() {
398 let a = PositionSpan::Discrete(vec![0, 1, 2, 3]);
399 let b = PositionSpan::Discrete(vec![2, 3, 4, 5]);
400 assert_ne!(a, b);
401 }
402
403 #[test]
406 fn test_eq_range_discrete_both_empty() {
407 let range = PositionSpan::range(0, 0);
408 let discrete = PositionSpan::Discrete(vec![]);
409 assert_eq!(range, discrete);
410 assert_eq!(discrete, range);
411 }
412
413 #[test]
414 fn test_eq_range_discrete_range_empty() {
415 let range = PositionSpan::range(0, 0);
416 let discrete = PositionSpan::Discrete(vec![0, 1, 2]);
417 assert_ne!(range, discrete);
418 assert_ne!(discrete, range);
419 }
420
421 #[test]
422 fn test_eq_range_discrete_discrete_empty() {
423 let range = PositionSpan::range(0, 3);
424 let discrete = PositionSpan::Discrete(vec![]);
425 assert_ne!(range, discrete);
426 assert_ne!(discrete, range);
427 }
428
429 #[test]
430 fn test_eq_range_discrete_equal() {
431 let range = PositionSpan::range(2, 5);
432 let discrete = PositionSpan::Discrete(vec![2, 3, 4]);
433 assert_eq!(range, discrete);
434 assert_eq!(discrete, range);
435 }
436
437 #[test]
438 fn test_eq_range_discrete_disjoint() {
439 let range = PositionSpan::range(0, 3);
440 let discrete = PositionSpan::Discrete(vec![5, 6, 7]);
441 assert_ne!(range, discrete);
442 assert_ne!(discrete, range);
443 }
444
445 #[test]
446 fn test_eq_range_discrete_overlapping_partial() {
447 let range = PositionSpan::range(0, 5);
448 let discrete = PositionSpan::Discrete(vec![2, 3, 4, 5, 6]);
449 assert_ne!(range, discrete);
450 assert_ne!(discrete, range);
451 }
452
453 #[test]
454 fn test_eq_range_discrete_subset() {
455 let range = PositionSpan::range(0, 10);
457 let discrete = PositionSpan::Discrete(vec![2, 3, 4]);
458 assert_ne!(range, discrete);
459 assert_ne!(discrete, range);
460 }
461
462 #[test]
463 fn test_eq_range_discrete_superset() {
464 let range = PositionSpan::range(5, 10);
466 let discrete = PositionSpan::Discrete(vec![3, 4, 5, 6, 7]);
467 assert_ne!(range, discrete);
468 assert_ne!(discrete, range);
469 }
470
471 #[test]
474 fn test_eq_empty_different_representation() {
475 let a = PositionSpan::range(0, 0);
476 let b = PositionSpan::Discrete(vec![]);
477 assert_eq!(a, b);
478 assert_eq!(b, a);
479 }
480}