use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
use crate::IndexType;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Interval<Ix> {
pub start: Ix,
pub end: Ix,
}
impl<Ix: IndexType> Interval<Ix> {
#[inline]
pub fn new(start: Ix, end: Ix) -> Self {
debug_assert!(start <= end, "Interval start must be <= end");
Interval { start, end }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.start == self.end
}
#[inline]
pub fn contains_point(&self, point: Ix) -> bool {
self.start <= point && point < self.end
}
#[inline]
pub fn overlaps(&self, other: &Interval<Ix>) -> bool {
self.start < other.end && other.start < self.end
}
#[inline]
pub fn touches(&self, other: &Interval<Ix>) -> bool {
self.start <= other.end && other.start <= self.end
}
#[inline]
pub fn to_range(&self) -> Range<Ix> {
self.start..self.end
}
}
impl<Ix: IndexType> From<Range<Ix>> for Interval<Ix> {
fn from(range: Range<Ix>) -> Self {
Interval::new(range.start, range.end)
}
}
impl<Ix: IndexType> From<Interval<Ix>> for Range<Ix> {
fn from(interval: Interval<Ix>) -> Self {
interval.start..interval.end
}
}
impl<Ix: IndexType> From<RangeInclusive<Ix>> for Interval<Ix> {
fn from(range: RangeInclusive<Ix>) -> Self {
let start = *range.start();
let end = range
.end()
.checked_add(&Ix::one())
.expect("RangeInclusive end is at MAX; cannot represent as half-open interval");
Interval::new(start, end)
}
}
impl<Ix: IndexType> From<RangeFrom<Ix>> for Interval<Ix> {
fn from(range: RangeFrom<Ix>) -> Self {
Interval::new(range.start, Ix::max_value())
}
}
impl<Ix: IndexType> From<RangeTo<Ix>> for Interval<Ix> {
fn from(range: RangeTo<Ix>) -> Self {
Interval::new(Ix::min_value(), range.end)
}
}
impl<Ix: IndexType> From<RangeFull> for Interval<Ix> {
fn from(_: RangeFull) -> Self {
Interval::new(Ix::min_value(), Ix::max_value())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_interval_new() {
let interval = Interval::new(0u32, 10);
assert_eq!(interval.start, 0);
assert_eq!(interval.end, 10);
}
#[test]
fn test_interval_is_empty() {
assert!(Interval::new(5u32, 5).is_empty());
assert!(!Interval::new(5u32, 10).is_empty());
}
#[test]
fn test_interval_contains_point() {
let interval = Interval::new(5u32, 10);
assert!(!interval.contains_point(4));
assert!(interval.contains_point(5));
assert!(interval.contains_point(7));
assert!(interval.contains_point(9));
assert!(!interval.contains_point(10));
}
#[test]
fn test_interval_overlaps() {
let a = Interval::new(0u32, 10);
let b = Interval::new(5, 15);
let c = Interval::new(10, 20);
let d = Interval::new(0, 5);
assert!(a.overlaps(&b)); assert!(!a.overlaps(&c)); assert!(a.overlaps(&d)); }
#[test]
fn test_interval_touches() {
let a = Interval::new(0u32, 10);
let b = Interval::new(5, 15);
let c = Interval::new(10, 20);
let d = Interval::new(20, 30);
assert!(a.touches(&b)); assert!(a.touches(&c)); assert!(!a.touches(&d)); }
#[test]
fn test_interval_from_range() {
let range = 5u32..10;
let interval: Interval<u32> = range.into();
assert_eq!(interval.start, 5);
assert_eq!(interval.end, 10);
}
#[test]
fn test_interval_from_range_inclusive() {
let interval: Interval<u32> = (5u32..=10).into();
assert_eq!(interval.start, 5);
assert_eq!(interval.end, 11); }
#[test]
fn test_interval_from_range_inclusive_at_zero() {
let interval: Interval<u8> = (0u8..=0).into();
assert_eq!(interval.start, 0);
assert_eq!(interval.end, 1);
}
#[test]
#[should_panic(expected = "RangeInclusive end is at MAX")]
fn test_interval_from_range_inclusive_overflow() {
let _interval: Interval<u8> = (0u8..=255).into();
}
#[test]
fn test_interval_from_range_from() {
let interval: Interval<u32> = (100u32..).into();
assert_eq!(interval.start, 100);
assert_eq!(interval.end, u32::MAX);
}
#[test]
fn test_interval_from_range_to() {
let interval: Interval<u32> = (..100u32).into();
assert_eq!(interval.start, u32::MIN);
assert_eq!(interval.end, 100);
}
#[test]
fn test_interval_from_range_to_signed() {
let interval: Interval<i32> = (..0i32).into();
assert_eq!(interval.start, i32::MIN);
assert_eq!(interval.end, 0);
}
#[test]
fn test_interval_from_range_full() {
let interval: Interval<u32> = (..).into();
assert_eq!(interval.start, u32::MIN);
assert_eq!(interval.end, u32::MAX);
}
#[test]
fn test_interval_from_range_full_signed() {
let interval: Interval<i16> = (..).into();
assert_eq!(interval.start, i16::MIN);
assert_eq!(interval.end, i16::MAX);
}
}