use std::cmp::Ordering;
use std::error::Error;
use std::fmt::Display;
use std::ops::RangeBounds;
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
use jiff::Timestamp;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::intervals::absolute::{
AbsBoundPair,
AbsEndBound,
AbsStartBound,
BoundedAbsInterval,
EmptiableAbsBoundPair,
EmptiableAbsInterval,
HalfBoundedAbsInterval,
HalfBoundedToFutureAbsInterval,
HalfBoundedToPastAbsInterval,
HasAbsBoundPair,
};
use crate::intervals::meta::{
Duration as IntervalDuration,
HasDuration,
HasIntervalTypeWithRel,
HasOpeningDirection,
HasOpenness,
HasRelativity,
Interval,
IntervalTypeWithRel,
IsEmpty,
OpeningDirection,
Openness,
Relativity,
};
use crate::intervals::special::UnboundedInterval;
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum AbsInterval {
Bounded(BoundedAbsInterval),
HalfBounded(HalfBoundedAbsInterval),
Unbounded(UnboundedInterval),
}
impl AbsInterval {
#[must_use]
pub fn from_range<R>(range: R) -> Self
where
R: RangeBounds<Timestamp>,
{
Self::from(AbsBoundPair::from_range(range))
}
#[must_use]
pub fn ord_by_start_and_inv_length(&self, other: &Self) -> Ordering {
self.abs_bound_pair()
.ord_by_start_and_inv_length(&other.abs_bound_pair())
}
#[must_use]
pub fn bounded(self) -> Option<BoundedAbsInterval> {
match self {
Self::Bounded(interval) => Some(interval),
_ => None,
}
}
#[must_use]
pub fn half_bounded(self) -> Option<HalfBoundedAbsInterval> {
match self {
Self::HalfBounded(interval) => Some(interval),
_ => None,
}
}
#[must_use]
pub fn unbounded(self) -> Option<UnboundedInterval> {
match self {
Self::Unbounded(interval) => Some(interval),
_ => None,
}
}
#[must_use]
pub fn to_emptiable(self) -> EmptiableAbsInterval {
EmptiableAbsInterval::from(self)
}
}
impl Interval for AbsInterval {}
impl HasAbsBoundPair for AbsInterval {
fn abs_bound_pair(&self) -> AbsBoundPair {
match self {
Self::Bounded(bounded) => bounded.abs_bound_pair(),
Self::HalfBounded(half_bounded) => half_bounded.abs_bound_pair(),
Self::Unbounded(unbounded) => unbounded.abs_bound_pair(),
}
}
fn abs_start(&self) -> AbsStartBound {
match self {
Self::Bounded(bounded) => bounded.abs_start(),
Self::HalfBounded(half_bounded) => half_bounded.abs_start(),
Self::Unbounded(unbounded) => unbounded.abs_start(),
}
}
fn abs_end(&self) -> AbsEndBound {
match self {
Self::Bounded(bounded) => bounded.abs_end(),
Self::HalfBounded(half_bounded) => half_bounded.abs_end(),
Self::Unbounded(unbounded) => unbounded.abs_end(),
}
}
}
impl HasDuration for AbsInterval {
fn duration(&self) -> IntervalDuration {
match self {
Self::Bounded(interval) => interval.duration(),
Self::HalfBounded(interval) => interval.duration(),
Self::Unbounded(interval) => interval.duration(),
}
}
}
impl HasRelativity for AbsInterval {
fn relativity(&self) -> Relativity {
match self {
Self::Bounded(interval) => interval.relativity(),
Self::HalfBounded(interval) => interval.relativity(),
Self::Unbounded(interval) => interval.relativity(),
}
}
}
impl HasOpenness for AbsInterval {
fn openness(&self) -> Openness {
match self {
Self::Bounded(interval) => interval.openness(),
Self::HalfBounded(interval) => interval.openness(),
Self::Unbounded(interval) => interval.openness(),
}
}
}
impl PartialOrd for AbsInterval {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AbsInterval {
fn cmp(&self, other: &Self) -> Ordering {
self.abs_bound_pair().cmp(&other.abs_bound_pair())
}
}
impl IsEmpty for AbsInterval {
fn is_empty(&self) -> bool {
false
}
}
impl HasIntervalTypeWithRel for AbsInterval {
fn interval_type_with_rel(&self) -> IntervalTypeWithRel {
match self {
Self::Bounded(_) => IntervalTypeWithRel::AbsBounded,
Self::HalfBounded(half_bounded) => IntervalTypeWithRel::AbsHalfBounded(half_bounded.opening_direction()),
Self::Unbounded(_) => IntervalTypeWithRel::Unbounded,
}
}
}
impl From<BoundedAbsInterval> for AbsInterval {
fn from(value: BoundedAbsInterval) -> Self {
Self::Bounded(value)
}
}
impl From<HalfBoundedToFutureAbsInterval> for AbsInterval {
fn from(value: HalfBoundedToFutureAbsInterval) -> Self {
Self::from(HalfBoundedAbsInterval::from(value))
}
}
impl From<HalfBoundedToPastAbsInterval> for AbsInterval {
fn from(value: HalfBoundedToPastAbsInterval) -> Self {
Self::from(HalfBoundedAbsInterval::from(value))
}
}
impl From<HalfBoundedAbsInterval> for AbsInterval {
fn from(value: HalfBoundedAbsInterval) -> Self {
Self::HalfBounded(value)
}
}
impl From<UnboundedInterval> for AbsInterval {
fn from(value: UnboundedInterval) -> Self {
Self::Unbounded(value)
}
}
impl From<AbsBoundPair> for AbsInterval {
fn from(value: AbsBoundPair) -> Self {
type StartB = AbsStartBound;
type EndB = AbsEndBound;
match (value.start(), value.end()) {
(StartB::InfinitePast, EndB::InfiniteFuture) => AbsInterval::Unbounded(UnboundedInterval),
(StartB::InfinitePast, EndB::Finite(finite_end)) => {
AbsInterval::HalfBounded(HalfBoundedAbsInterval::new(finite_end.pos(), OpeningDirection::ToPast))
},
(StartB::Finite(finite_start), EndB::InfiniteFuture) => AbsInterval::HalfBounded(
HalfBoundedAbsInterval::new(finite_start.pos(), OpeningDirection::ToFuture),
),
(StartB::Finite(finite_start), EndB::Finite(finite_end)) => {
AbsInterval::Bounded(BoundedAbsInterval::unchecked_new(finite_start, finite_end))
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AbsIntervalTryFromEmptiableAbsBoundPairError;
impl Display for AbsIntervalTryFromEmptiableAbsBoundPairError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Failed to convert the emptiable absolute bound pair into an absolute interval"
)
}
}
impl Error for AbsIntervalTryFromEmptiableAbsBoundPairError {}
impl TryFrom<EmptiableAbsBoundPair> for AbsInterval {
type Error = AbsIntervalTryFromEmptiableAbsBoundPairError;
fn try_from(value: EmptiableAbsBoundPair) -> Result<Self, Self::Error> {
Ok(Self::from(
value.bound().ok_or(AbsIntervalTryFromEmptiableAbsBoundPairError)?,
))
}
}