use core::ops::{Bound, Range, RangeBounds, RangeInclusive};
use crate::utils::{invalid_interval_panic, sorted_config, SortedConfig};
use crate::{IntervalType, PointType};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Interval<I> {
pub(crate) start: I,
pub(crate) end: I,
}
impl<I> Interval<I>
where
I: PointType,
{
pub fn start(&self) -> &I {
&self.start
}
pub fn end(&self) -> &I {
&self.end
}
}
impl<I> RangeBounds<I> for Interval<I>
where
I: PointType,
{
fn start_bound(&self) -> Bound<&I> {
Bound::Included(&self.start)
}
fn end_bound(&self) -> Bound<&I> {
Bound::Included(&self.end)
}
}
impl<I> InclusiveInterval<I> for Interval<I>
where
I: PointType,
{
fn start(&self) -> &I {
&self.start
}
fn end(&self) -> &I {
&self.end
}
}
impl<I> From<Interval<I>> for RangeInclusive<I> {
fn from(value: Interval<I>) -> Self {
value.start..=value.end
}
}
impl<I> From<RangeInclusive<I>> for Interval<I>
where
I: PointType,
{
fn from(value: RangeInclusive<I>) -> Self {
ii(value.start().clone(), value.end().clone())
}
}
impl<I> From<Interval<I>> for Range<I>
where
I: PointType,
{
fn from(value: Interval<I>) -> Self {
value.start..value.end.up().unwrap()
}
}
impl<I> From<Range<I>> for Interval<I>
where
I: PointType,
{
fn from(value: Range<I>) -> Self {
ie(value.start, value.end)
}
}
pub fn uu<I>() -> Interval<I>
where
I: PointType,
{
let interval = Interval {
start: I::min_value(),
end: I::max_value(),
};
invalid_interval_panic(&interval);
interval
}
pub fn ui<I>(end: I) -> Interval<I>
where
I: PointType,
{
let interval = Interval { start: I::min_value(), end };
invalid_interval_panic(&interval);
interval
}
pub fn ue<I>(end: I) -> Interval<I>
where
I: PointType,
{
let interval = Interval {
start: I::min_value(),
end: end.down().unwrap(),
};
invalid_interval_panic(&interval);
interval
}
pub fn iu<I>(start: I) -> Interval<I>
where
I: PointType,
{
let interval = Interval { start, end: I::max_value() };
invalid_interval_panic(&interval);
interval
}
pub fn eu<I>(start: I) -> Interval<I>
where
I: PointType,
{
let interval = Interval {
start: start.up().unwrap(),
end: I::max_value(),
};
invalid_interval_panic(&interval);
interval
}
pub fn ii<I>(start: I, end: I) -> Interval<I>
where
I: PointType,
{
let interval = Interval { start, end };
invalid_interval_panic(&interval);
interval
}
pub fn ie<I>(start: I, end: I) -> Interval<I>
where
I: PointType,
{
let interval = Interval {
start,
end: end.down().unwrap(),
};
invalid_interval_panic(&interval);
interval
}
pub fn ei<I>(start: I, end: I) -> Interval<I>
where
I: PointType,
{
let interval = Interval {
start: start.up().unwrap(),
end,
};
invalid_interval_panic(&interval);
interval
}
pub fn ee<I>(start: I, end: I) -> Interval<I>
where
I: PointType,
{
let interval = Interval {
start: start.up().unwrap(),
end: end.down().unwrap(),
};
invalid_interval_panic(&interval);
interval
}
pub trait InclusiveInterval<I>: Clone + From<Interval<I>> {
fn start(&self) -> &I;
fn end(&self) -> &I;
fn contains_point(&self, point: &I) -> bool
where
I: PointType,
{
point >= self.start() && point <= self.end()
}
fn contains_interval<Q>(&self, interval: &Q) -> bool
where
I: PointType,
Q: IntervalType<I>,
{
self.start() <= interval.start() && self.end() >= interval.end()
}
fn is_valid(&self) -> bool
where
I: PointType,
{
self.start() <= self.end()
}
fn is_singular(&self) -> bool
where
I: PointType,
{
self.start() == self.end()
}
fn intersection<Q>(&self, other: &Q) -> Option<Self>
where
I: PointType,
Q: IntervalType<I>,
Self: From<Interval<I>>,
{
let intersect_start = I::max(self.start().clone(), other.start().clone());
let intersect_end = I::min(self.end().clone(), other.end().clone());
if intersect_start <= intersect_end {
Some(Self::from(Interval {
start: intersect_start,
end: intersect_end,
}))
} else {
None
}
}
fn overlaps<Q>(&self, other: &Q) -> bool
where
I: PointType,
Q: IntervalType<I>,
{
!matches!(
sorted_config( (*self).clone(), (*other).clone()),
SortedConfig::NonOverlapping(_, _)
)
}
fn translate(&self, delta: I) -> Self
where
I: PointType,
I: core::ops::Add<Output = I>,
Self: From<Interval<I>>,
{
Self::from(Interval {
start: self.start().clone() + delta.clone(),
end: self.end().clone() + delta,
})
}
fn width(&self) -> I
where
I: PointType,
I: core::ops::Sub<Output = I>,
{
self.end().clone().clone() - self.start().clone()
}
}