use crate::error::{Error, err};
use core::ops::{Bound, Range, RangeBounds};
use jiff::civil::DateTime;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DateTimeRange {
pub(crate) start: DateTime,
pub(crate) end: DateTime,
pub(crate) fixpoint: Option<DateTime>,
}
impl DateTimeRange {
#[inline]
pub(crate) const fn new(start: DateTime, end: DateTime) -> DateTimeRange {
DateTimeRange {
start,
end,
fixpoint: None,
}
}
#[inline]
pub(crate) fn with_fixpoint(mut self, fixpoint: DateTime) -> Result<DateTimeRange, Error> {
if fixpoint > self.start {
return Err(err!(
"fixpoint ({fixpoint}) must be less than or equal to range start ({})",
self.start
));
}
self.fixpoint = Some(fixpoint);
Ok(self)
}
#[inline]
pub(crate) fn intersect(&self, other: DateTimeRange) -> Result<DateTimeRange, Error> {
let start = self.start.max(other.start);
let end = self.end.min(other.end);
if start >= end {
return Err(Error::datetime_range("series intersection", start..end));
}
DateTimeRange::new(start, end).with_fixpoint(self.fixpoint())
}
#[inline]
pub(crate) fn fixpoint(&self) -> DateTime {
self.fixpoint.unwrap_or(self.start)
}
#[inline]
pub const fn start(&self) -> DateTime {
self.start
}
#[inline]
pub const fn end(&self) -> DateTime {
self.end
}
}
impl RangeBounds<DateTime> for DateTimeRange {
fn start_bound(&self) -> Bound<&DateTime> {
Bound::Included(&self.start)
}
fn end_bound(&self) -> Bound<&DateTime> {
Bound::Excluded(&self.end)
}
}
impl From<DateTimeRange> for Range<DateTime> {
fn from(range: DateTimeRange) -> Self {
range.start..range.end
}
}
impl From<Range<DateTime>> for DateTimeRange {
fn from(range: Range<DateTime>) -> Self {
DateTimeRange::new(range.start, range.end)
}
}