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