1#[derive(Debug, PartialEq, Eq, Clone, Copy)]
154pub enum RangeOverlap {
155 AContainsB,
157
158 AInsideB,
160
161 AEndsInB,
165
166 AStartsInB,
170
171 AEqualsB,
173
174 None
176}
177
178impl RangeOverlap {
179 pub fn has_overlap(&self) -> bool {
181 if let Self::None = self {
182 false
183 } else {
184 true
185 }
186 }
187}
188
189pub fn excl_classify<T: PartialOrd>(a_start: T, a_end: T, b_start: T, b_end: T) -> RangeOverlap {
192 if a_start == b_start && a_end == b_end {
193 RangeOverlap::AEqualsB
194 } else if a_start <= b_start && a_end >= b_end {
195 RangeOverlap::AContainsB
196 } else if a_start < b_start && a_end > b_start && a_end <= b_end {
197 RangeOverlap::AEndsInB
198 } else if a_start > b_start && a_start < b_end && a_end > b_end {
199 RangeOverlap::AStartsInB
200 } else if a_start >= b_end || b_start >= a_end {
201 RangeOverlap::None
202 } else {
203 RangeOverlap::AInsideB
204 }
205}
206
207pub fn incl_classify<T: PartialOrd>(a_start: T, a_end: T, b_start: T, b_end: T) -> RangeOverlap {
210 if a_start == b_start && a_end == b_end {
211 RangeOverlap::AEqualsB
212 } else if a_start <= b_start && a_end >= b_end {
213 RangeOverlap::AContainsB
214 } else if a_start < b_start && a_end >= b_start && a_end <= b_end {
215 RangeOverlap::AEndsInB
216 } else if a_start > b_start && a_start <= b_end && a_end > b_end {
217 RangeOverlap::AStartsInB
218 } else if a_start >= b_end || b_start >= a_end {
219 RangeOverlap::None
220 } else {
221 RangeOverlap::AInsideB
222 }
223}
224
225pub fn classify_any<T: PartialOrd>(a_start: Option<T>, a_end: Option<T>, b_start: Option<T>, b_end: Option<T>, inclusive: bool) -> RangeOverlap {
231 match (a_start, a_end, b_start, b_end, inclusive) {
232 (None, None, None, None, _) => RangeOverlap::AEqualsB,
233 (None, None, None, Some(_), _) => RangeOverlap::AContainsB,
234 (None, None, Some(_), None, _) => RangeOverlap::AContainsB,
235 (None, None, Some(_), Some(_), _) => RangeOverlap::AContainsB,
236 (None, Some(_), None, None, _) => RangeOverlap::AInsideB,
237 (None, Some(ea), None, Some(eb), _) => {
238 if ea == eb {
241 RangeOverlap::AEqualsB
242 } else if ea < eb {
243 RangeOverlap::AInsideB
244 } else {
245 RangeOverlap::AContainsB
246 }
247 },
248 (None, Some(ea), Some(sb), None, false) => {
249 if ea <= sb {
250 RangeOverlap::None
251 } else {
252 RangeOverlap::AEndsInB
253 }
254 },
255 (None, Some(ea), Some(sb), None, true) => {
256 if ea < sb {
257 RangeOverlap::None
258 } else {
259 RangeOverlap::AEndsInB
260 }
261 },
262 (None, Some(ea), Some(sb), Some(eb), false) => {
263 if ea <= sb {
264 RangeOverlap::None
265 } else if ea > sb && ea < eb {
266 RangeOverlap::AEndsInB
267 } else {
268 RangeOverlap::AContainsB
269 }
270 },
271 (None, Some(ea), Some(sb), Some(eb), true) => {
272 if ea < sb {
273 RangeOverlap::None
274 } else if ea >= sb && ea < eb {
275 RangeOverlap::AEndsInB
276 } else {
277 RangeOverlap::AContainsB
278 }
279 },
280 (Some(_), None, None, None, _) => RangeOverlap::AInsideB,
281 (Some(sa), None, None, Some(eb), false) => {
282 if sa >= eb {
283 RangeOverlap::None
284 } else {
285 RangeOverlap::AStartsInB
286 }
287 },
288 (Some(sa), None, None, Some(eb), true) => {
289 if sa > eb {
290 RangeOverlap::None
291 } else {
292 RangeOverlap::AStartsInB
293 }
294 },
295 (Some(sa), None, Some(sb), None, _) => {
296 if sa == sb {
297 RangeOverlap::AEqualsB
298 } else if sa < sb {
299 RangeOverlap::AContainsB
300 } else {
301 RangeOverlap::AInsideB
302 }
303 },
304 (Some(sa), None, Some(sb), Some(eb), false) => {
305 if sa <= sb {
306 RangeOverlap::AContainsB
307 } else if sa < eb {
308 RangeOverlap::AStartsInB
309 } else {
310 RangeOverlap::None
311 }
312 },
313 (Some(sa), None, Some(sb), Some(eb), true) => {
314 if sa <= sb {
315 RangeOverlap::AContainsB
316 } else if sa <= eb {
317 RangeOverlap::AStartsInB
318 } else {
319 RangeOverlap::None
320 }
321 },
322 (Some(_), Some(_), None, None, _) => RangeOverlap::AInsideB,
323 (Some(sa), Some(ea), None, Some(eb), false) => {
324 if eb <= sa {
325 RangeOverlap::None
326 } else if ea <= eb {
327 RangeOverlap::AInsideB
328 } else {
329 RangeOverlap::AStartsInB
330 }
331 },
332 (Some(sa), Some(ea), None, Some(eb), true) => {
333 if eb < sa {
334 RangeOverlap::None
335 } else if ea <= eb {
336 RangeOverlap::AInsideB
337 } else {
338 RangeOverlap::AStartsInB
339 }
340 },
341 (Some(sa), Some(ea), Some(sb), None, false) => {
342 if sb >= ea {
343 RangeOverlap::None
344 } else if sa >= sb {
345 RangeOverlap::AInsideB
346 } else {
347 RangeOverlap::AEndsInB
348 }
349 },
350 (Some(sa), Some(ea), Some(sb), None, true) => {
351 if sb > ea {
352 RangeOverlap::None
353 } else if sa >= sb {
354 RangeOverlap::AInsideB
355 } else {
356 RangeOverlap::AEndsInB
357 }
358 },
359 (Some(sa), Some(ea), Some(sb), Some(eb), false) => {
360 excl_classify(sa, ea, sb, eb)
361 },
362 (Some(sa), Some(ea), Some(sb), Some(eb), true) => {
363 incl_classify(sa, ea, sb, eb)
364 },
365 }
366}
367
368pub fn has_excl_overlap<T: PartialOrd>(a_start: T, a_end: T, b_start: T, b_end: T) -> bool {
371 excl_classify(a_start, a_end, b_start, b_end).has_overlap()
372}
373
374pub fn has_incl_overlap<T: PartialOrd>(a_start: T, a_end: T, b_start: T, b_end: T) -> bool {
377 incl_classify(a_start, a_end, b_start, b_end).has_overlap()
378}
379
380pub fn has_open_excl_overlap<T: PartialOrd>(a_start: Option<T>, a_end: Option<T>, b_start: Option<T>, b_end: Option<T>) -> bool {
384 classify_any(a_start, a_end, b_start, b_end, false).has_overlap()
385}
386
387pub fn has_open_incl_overlap<T: PartialOrd>(a_start: Option<T>, a_end: Option<T>, b_start: Option<T>, b_end: Option<T>) -> bool {
391 classify_any(a_start, a_end, b_start, b_end, true).has_overlap()
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn test_open_range_exclusive_bool() {
400 let r1_start = 1;
401 let r1_end = 20;
402 let r2_before = -20;
403 let r2_before2 = -10;
404 let r2_between = 10;
405 let r2_after = 30;
406 let r2_after2 = 40;
407
408 assert_eq!(has_open_excl_overlap(Some(r1_start), None, Some(r2_before), None), true);
410 assert_eq!(has_open_excl_overlap(Some(r1_start), None, Some(r2_between), None), true);
411 assert_eq!(has_open_excl_overlap(Some(r1_start), None, Some(r2_after), None), true);
412
413 assert_eq!(has_open_excl_overlap(Some(r2_before), None, Some(r1_start), None), true);
414 assert_eq!(has_open_excl_overlap(Some(r2_between), None, Some(r1_start), None), true);
415 assert_eq!(has_open_excl_overlap(Some(r2_after), None, Some(r1_start), None), true);
416
417 assert_eq!(has_open_excl_overlap(Some(r1_start), Some(r1_end), Some(r2_before), None), true);
421 assert_eq!(has_open_excl_overlap(Some(r1_start), Some(r1_end), Some(r2_between), None), true);
422 assert_eq!(has_open_excl_overlap(Some(r1_start), Some(r1_end), Some(r2_after), None), false);
423
424 assert_eq!(has_open_excl_overlap(Some(r2_before), None, Some(r1_start), Some(r1_end)), true);
425 assert_eq!(has_open_excl_overlap(Some(r2_between), None, Some(r1_start), Some(r1_end)), true);
426 assert_eq!(has_open_excl_overlap(Some(r2_after), None, Some(r1_start), Some(r1_end)), false);
427
428 assert_eq!(has_open_excl_overlap(Some(r1_start), Some(r1_end), Some(r2_before), Some(r2_before2)), false);
431 assert_eq!(has_open_excl_overlap(Some(r1_start), Some(r1_end), Some(r2_before), Some(r2_between)), true);
432 assert_eq!(has_open_excl_overlap(Some(r1_start), Some(r1_end), Some(r2_between), Some(r2_after)), true);
433 assert_eq!(has_open_excl_overlap(Some(r1_start), Some(r1_end), Some(r2_after), Some(r2_after2)), false);
434
435 assert_eq!(has_open_excl_overlap(Some(r2_before), Some(r2_before2), Some(r1_start), Some(r1_end)), false);
436 assert_eq!(has_open_excl_overlap(Some(r2_before), Some(r2_between), Some(r1_start), Some(r1_end)), true);
437 assert_eq!(has_open_excl_overlap(Some(r2_between), Some(r2_after), Some(r1_start), Some(r1_end)), true);
438 assert_eq!(has_open_excl_overlap(Some(r2_after), Some(r2_after2), Some(r1_start), Some(r1_end)), false);
439 }
440
441 #[test]
442 fn test_open_range_exclusive_classification() {
443 assert_eq!(classify_any(Some(1), Some(10), Some(1), Some(10), false), RangeOverlap::AEqualsB);
445 assert_eq!(classify_any(None, Some(10), None, Some(10), false), RangeOverlap::AEqualsB);
446 assert_eq!(classify_any(Some(1), None, Some(1), None, false), RangeOverlap::AEqualsB);
447 assert_eq!(classify_any::<i32>(None, None, None, None, false), RangeOverlap::AEqualsB);
448
449 assert_eq!(classify_any(Some(1), Some(100), Some(50), Some(60), false), RangeOverlap::AContainsB);
451 assert_eq!(classify_any(None, Some(100), Some(50), Some(60), false), RangeOverlap::AContainsB);
452 assert_eq!(classify_any(Some(1), None, Some(50), Some(60), false), RangeOverlap::AContainsB);
453 assert_eq!(classify_any(None, None, Some(50), Some(60), false), RangeOverlap::AContainsB);
454 assert_eq!(classify_any(None, Some(100), None, Some(60), false), RangeOverlap::AContainsB);
455 assert_eq!(classify_any(Some(1), None, Some(50), None, false), RangeOverlap::AContainsB);
456 assert_eq!(classify_any(None, None, None, Some(60), false), RangeOverlap::AContainsB);
457 assert_eq!(classify_any(None, None, Some(50), None, false), RangeOverlap::AContainsB);
458
459 assert_eq!(classify_any(None, Some(50), Some(1), Some(50), false), RangeOverlap::AContainsB);
461 assert_eq!(classify_any(Some(1), None, Some(1), Some(50), false), RangeOverlap::AContainsB);
462 assert_eq!(classify_any(Some(10), Some(50), Some(10), Some(20), false), RangeOverlap::AContainsB);
463 assert_eq!(classify_any(Some(10), Some(50), Some(40), Some(50), false), RangeOverlap::AContainsB);
464
465 assert_eq!(classify_any(None, Some(75), None, None, false), RangeOverlap::AInsideB);
467 assert_eq!(classify_any(Some(50), None, None, None, false), RangeOverlap::AInsideB);
468 assert_eq!(classify_any(Some(50), Some(60), Some(1), Some(100), false), RangeOverlap::AInsideB);
469 assert_eq!(classify_any(Some(50), Some(60), None, Some(100), false), RangeOverlap::AInsideB);
470 assert_eq!(classify_any(Some(50), Some(60), Some(1), None, false), RangeOverlap::AInsideB);
471 assert_eq!(classify_any(None, Some(60), None, Some(100), false), RangeOverlap::AInsideB);
472 assert_eq!(classify_any(Some(50), None, Some(1), None, false), RangeOverlap::AInsideB);
473
474 assert_eq!(classify_any(Some(1), Some(50), Some(1), None, false), RangeOverlap::AInsideB);
476 assert_eq!(classify_any(Some(1), Some(50), None, Some(50), false), RangeOverlap::AInsideB);
477
478 assert_eq!(classify_any(Some(1), Some(335), Some(1), None, false), RangeOverlap::AInsideB);
482 assert_eq!(classify_any(Some(336), Some(366), Some(183), Some(366), false), RangeOverlap::AInsideB);
484
485 assert_eq!(classify_any(Some(1), Some(75), Some(25), Some(99), false), RangeOverlap::AEndsInB);
487 assert_eq!(classify_any(None, Some(75), Some(25), Some(99), false), RangeOverlap::AEndsInB);
488 assert_eq!(classify_any(None, Some(75), Some(25), None, false), RangeOverlap::AEndsInB);
489
490 assert_eq!(classify_any(Some(50), Some(99), Some(1), Some(75), false), RangeOverlap::AStartsInB);
492 assert_eq!(classify_any(Some(50), None, Some(1), Some(75), false), RangeOverlap::AStartsInB);
493 assert_eq!(classify_any(Some(50), None, None, Some(75), false), RangeOverlap::AStartsInB);
494
495 assert_eq!(classify_any(Some(1), Some(25), Some(50), Some(75), false), RangeOverlap::None);
497 assert_eq!(classify_any(Some(50), Some(75), Some(1), Some(25), false), RangeOverlap::None);
498 assert_eq!(classify_any(None, Some(25), Some(50), Some(99), false), RangeOverlap::None);
499 assert_eq!(classify_any(Some(1), Some(25), Some(50), None, false), RangeOverlap::None);
500
501 }
502
503 #[test]
504 fn test_open_range_inclusive_classification() {
505 assert_eq!(classify_any(Some(1), Some(10), Some(1), Some(10), true), RangeOverlap::AEqualsB);
507 assert_eq!(classify_any(None, Some(10), None, Some(10), true), RangeOverlap::AEqualsB);
508 assert_eq!(classify_any(Some(1), None, Some(1), None, true), RangeOverlap::AEqualsB);
509 assert_eq!(classify_any::<i32>(None, None, None, None, true), RangeOverlap::AEqualsB);
510
511 assert_eq!(classify_any(Some(1), Some(100), Some(50), Some(60), true), RangeOverlap::AContainsB);
513 assert_eq!(classify_any(None, Some(100), Some(50), Some(60), true), RangeOverlap::AContainsB);
514 assert_eq!(classify_any(Some(1), None, Some(50), Some(60), true), RangeOverlap::AContainsB);
515 assert_eq!(classify_any(None, None, Some(50), Some(60), true), RangeOverlap::AContainsB);
516 assert_eq!(classify_any(None, Some(100), None, Some(60), true), RangeOverlap::AContainsB);
517 assert_eq!(classify_any(Some(1), None, Some(50), None, true), RangeOverlap::AContainsB);
518 assert_eq!(classify_any(None, None, None, Some(60), true), RangeOverlap::AContainsB);
519 assert_eq!(classify_any(None, None, Some(50), None, true), RangeOverlap::AContainsB);
520
521 assert_eq!(classify_any(None, Some(50), Some(1), Some(50), true), RangeOverlap::AContainsB);
523 assert_eq!(classify_any(Some(1), None, Some(1), Some(50), true), RangeOverlap::AContainsB);
524 assert_eq!(classify_any(Some(10), Some(50), Some(10), Some(20), true), RangeOverlap::AContainsB);
525 assert_eq!(classify_any(Some(10), Some(50), Some(40), Some(50), true), RangeOverlap::AContainsB);
526
527 assert_eq!(classify_any(None, Some(75), None, None, true), RangeOverlap::AInsideB);
529 assert_eq!(classify_any(Some(50), None, None, None, true), RangeOverlap::AInsideB);
530 assert_eq!(classify_any(Some(50), Some(60), Some(1), Some(100), true), RangeOverlap::AInsideB);
531 assert_eq!(classify_any(Some(50), Some(60), None, Some(100), true), RangeOverlap::AInsideB);
532 assert_eq!(classify_any(Some(50), Some(60), Some(1), None, true), RangeOverlap::AInsideB);
533 assert_eq!(classify_any(None, Some(60), None, Some(100), true), RangeOverlap::AInsideB);
534 assert_eq!(classify_any(Some(50), None, Some(1), None, true), RangeOverlap::AInsideB);
535
536 assert_eq!(classify_any(Some(1), Some(50), Some(1), None, true), RangeOverlap::AInsideB);
538 assert_eq!(classify_any(Some(1), Some(50), None, Some(50), true), RangeOverlap::AInsideB);
539
540 assert_eq!(classify_any(Some(1), Some(335), Some(1), None, true), RangeOverlap::AInsideB);
544 assert_eq!(classify_any(Some(336), Some(366), Some(183), Some(366), true), RangeOverlap::AInsideB);
546
547 assert_eq!(classify_any(Some(1), Some(75), Some(25), Some(99), true), RangeOverlap::AEndsInB);
549 assert_eq!(classify_any(None, Some(75), Some(25), Some(99), true), RangeOverlap::AEndsInB);
550 assert_eq!(classify_any(None, Some(75), Some(25), None, true), RangeOverlap::AEndsInB);
551
552 assert_eq!(classify_any(Some(50), Some(99), Some(1), Some(75), true), RangeOverlap::AStartsInB);
554 assert_eq!(classify_any(Some(50), None, Some(1), Some(75), true), RangeOverlap::AStartsInB);
555 assert_eq!(classify_any(Some(50), None, None, Some(75), true), RangeOverlap::AStartsInB);
556
557 assert_eq!(classify_any(Some(1), Some(25), Some(50), Some(75), true), RangeOverlap::None);
559 assert_eq!(classify_any(Some(50), Some(75), Some(1), Some(25), true), RangeOverlap::None);
560 assert_eq!(classify_any(None, Some(25), Some(50), Some(99), true), RangeOverlap::None);
561 assert_eq!(classify_any(Some(1), Some(25), Some(50), None, true), RangeOverlap::None);
562
563 }
564
565 #[test]
566 fn test_exclusive_vs_inclusive() {
567 assert_eq!(excl_classify(1, 5, 5, 10), RangeOverlap::None);
568 assert_eq!(incl_classify(1, 5, 5, 10), RangeOverlap::AEndsInB);
569
570 assert_eq!(excl_classify(10, 15, 5, 10), RangeOverlap::None);
571 assert_eq!(incl_classify(10, 15, 5, 10), RangeOverlap::AStartsInB);
572
573 assert_eq!(classify_any(None, Some(10), Some(10), None, false), RangeOverlap::None);
574 assert_eq!(classify_any(None, Some(10), Some(10), None, true), RangeOverlap::AEndsInB);
575
576 assert_eq!(classify_any(None, Some(10), Some(10), Some(20), false), RangeOverlap::None);
577 assert_eq!(classify_any(None, Some(10), Some(10), Some(20), true), RangeOverlap::AEndsInB);
578
579 assert_eq!(classify_any(Some(1), None, None, Some(1), false), RangeOverlap::None);
580 assert_eq!(classify_any(Some(1), None, None, Some(1), true), RangeOverlap::AStartsInB);
581
582 assert_eq!(classify_any(Some(1), None, Some(-5), Some(1), false), RangeOverlap::None);
583 assert_eq!(classify_any(Some(1), None, Some(-5), Some(1), true), RangeOverlap::AStartsInB);
584
585 assert_eq!(classify_any(Some(1), Some(10), None, Some(1), false), RangeOverlap::None);
586 assert_eq!(classify_any(Some(1), Some(10), None, Some(1), true), RangeOverlap::AStartsInB);
587
588 assert_eq!(classify_any(Some(1), Some(10), Some(10), None, false), RangeOverlap::None);
589 assert_eq!(classify_any(Some(1), Some(10), Some(10), None, true), RangeOverlap::AEndsInB);
590
591
592 }
593
594}