use std::cmp::Ordering;
use std::ops::RangeBounds;
use std::time::Duration;
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
use jiff::SignedDuration;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::intervals::meta::{
BoundInclusivity,
Duration as IntervalDuration,
Epsilon,
HasDuration,
HasIntervalTypeWithRel,
HasOpenness,
HasRelativity,
Interval,
IntervalTypeWithRel,
IsEmpty,
Openness,
Relativity,
};
use crate::intervals::relative::{
BoundedRelInterval,
EmptiableRelInterval,
HalfBoundedRelInterval,
HasRelBoundPair,
RelBoundPair,
RelEndBound,
RelInterval,
RelStartBound,
};
use crate::intervals::special::{EmptyInterval, UnboundedInterval};
pub trait HasEmptiableRelBoundPair {
#[must_use]
fn emptiable_rel_bound_pair(&self) -> EmptiableRelBoundPair;
#[must_use]
fn partial_rel_start(&self) -> Option<RelStartBound>;
#[must_use]
fn partial_rel_end(&self) -> Option<RelEndBound>;
}
impl<T> HasEmptiableRelBoundPair for T
where
T: HasRelBoundPair,
{
fn emptiable_rel_bound_pair(&self) -> EmptiableRelBoundPair {
EmptiableRelBoundPair::Bound(self.rel_bound_pair())
}
fn partial_rel_start(&self) -> Option<RelStartBound> {
Some(self.rel_start())
}
fn partial_rel_end(&self) -> Option<RelEndBound> {
Some(self.rel_end())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum EmptiableRelBoundPair {
Bound(RelBoundPair),
Empty,
}
impl EmptiableRelBoundPair {
#[must_use]
pub fn from_range<R>(range: R) -> Self
where
R: RangeBounds<SignedDuration>,
{
RelBoundPair::from_range(range).to_emptiable()
}
#[must_use]
pub fn ord_by_start_and_inv_length(&self, other: &Self) -> Ordering {
if let EmptiableRelBoundPair::Bound(lhs_rel_bound_pair) = self
&& let EmptiableRelBoundPair::Bound(rhs_rel_bound_pair) = other
{
lhs_rel_bound_pair.ord_by_start_and_inv_length(rhs_rel_bound_pair)
} else {
self.cmp(other)
}
}
#[must_use]
pub fn bound(self) -> Option<RelBoundPair> {
match self {
EmptiableRelBoundPair::Bound(bound) => Some(bound),
EmptiableRelBoundPair::Empty => None,
}
}
#[must_use]
pub fn to_emptiable_interval(self) -> EmptiableRelInterval {
EmptiableRelInterval::from(self)
}
}
impl Interval for EmptiableRelBoundPair {}
impl HasEmptiableRelBoundPair for EmptiableRelBoundPair {
fn emptiable_rel_bound_pair(&self) -> EmptiableRelBoundPair {
self.clone()
}
fn partial_rel_start(&self) -> Option<RelStartBound> {
match self {
Self::Bound(bounds) => Some(bounds.start()),
Self::Empty => None,
}
}
fn partial_rel_end(&self) -> Option<RelEndBound> {
match self {
Self::Bound(bounds) => Some(bounds.end()),
Self::Empty => None,
}
}
}
impl IsEmpty for EmptiableRelBoundPair {
fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
}
impl HasDuration for EmptiableRelBoundPair {
fn duration(&self) -> IntervalDuration {
match self {
Self::Bound(bound) => bound.duration(),
Self::Empty => IntervalDuration::Finite(Duration::ZERO, Epsilon::None),
}
}
}
impl HasOpenness for EmptiableRelBoundPair {
fn openness(&self) -> Openness {
match self {
Self::Bound(bound) => bound.openness(),
Self::Empty => Openness::Empty,
}
}
}
impl HasRelativity for EmptiableRelBoundPair {
fn relativity(&self) -> Relativity {
match self {
Self::Bound(bound) => bound.relativity(),
Self::Empty => Relativity::Any,
}
}
}
impl HasIntervalTypeWithRel for EmptiableRelBoundPair {
fn interval_type_with_rel(&self) -> IntervalTypeWithRel {
match self {
Self::Empty => IntervalTypeWithRel::Empty,
Self::Bound(bound_pair) => bound_pair.interval_type_with_rel(),
}
}
}
impl PartialOrd for EmptiableRelBoundPair {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for EmptiableRelBoundPair {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(EmptiableRelBoundPair::Empty, EmptiableRelBoundPair::Empty) => Ordering::Equal,
(EmptiableRelBoundPair::Empty, EmptiableRelBoundPair::Bound(_)) => Ordering::Less,
(EmptiableRelBoundPair::Bound(_), EmptiableRelBoundPair::Empty) => Ordering::Greater,
(EmptiableRelBoundPair::Bound(og_rel_bound_pair), EmptiableRelBoundPair::Bound(other_rel_bound_pair)) => {
og_rel_bound_pair.cmp(other_rel_bound_pair)
},
}
}
}
impl From<Option<(RelStartBound, RelEndBound)>> for EmptiableRelBoundPair {
fn from(opt_start_end: Option<(RelStartBound, RelEndBound)>) -> Self {
if let Some((start, end)) = opt_start_end {
Self::from(RelBoundPair::new(start, end))
} else {
Self::Empty
}
}
}
impl From<Option<(Option<SignedDuration>, Option<SignedDuration>)>> for EmptiableRelBoundPair {
fn from(opt_start_opt_end_opt: Option<(Option<SignedDuration>, Option<SignedDuration>)>) -> Self {
if let Some((start_opt, end_opt)) = opt_start_opt_end_opt {
Self::from(RelBoundPair::new(
RelStartBound::from(start_opt),
RelEndBound::from(end_opt),
))
} else {
Self::Empty
}
}
}
impl
From<
Option<(
Option<(SignedDuration, BoundInclusivity)>,
Option<(SignedDuration, BoundInclusivity)>,
)>,
> for EmptiableRelBoundPair
{
fn from(
opt_start_incl_opt_end_incl_opt: Option<(
Option<(SignedDuration, BoundInclusivity)>,
Option<(SignedDuration, BoundInclusivity)>,
)>,
) -> Self {
if let Some((start_incl_opt, end_incl_opt)) = opt_start_incl_opt_end_incl_opt {
Self::from(RelBoundPair::new(
RelStartBound::from(start_incl_opt),
RelEndBound::from(end_incl_opt),
))
} else {
Self::Empty
}
}
}
impl From<RelBoundPair> for EmptiableRelBoundPair {
fn from(value: RelBoundPair) -> Self {
EmptiableRelBoundPair::Bound(value)
}
}
impl From<BoundedRelInterval> for EmptiableRelBoundPair {
fn from(value: BoundedRelInterval) -> Self {
value.emptiable_rel_bound_pair()
}
}
impl From<HalfBoundedRelInterval> for EmptiableRelBoundPair {
fn from(value: HalfBoundedRelInterval) -> Self {
value.emptiable_rel_bound_pair()
}
}
impl From<RelInterval> for EmptiableRelBoundPair {
fn from(value: RelInterval) -> Self {
value.emptiable_rel_bound_pair()
}
}
impl From<EmptiableRelInterval> for EmptiableRelBoundPair {
fn from(value: EmptiableRelInterval) -> Self {
value.emptiable_rel_bound_pair()
}
}
impl From<UnboundedInterval> for EmptiableRelBoundPair {
fn from(value: UnboundedInterval) -> Self {
value.emptiable_rel_bound_pair()
}
}
impl From<EmptyInterval> for EmptiableRelBoundPair {
fn from(value: EmptyInterval) -> Self {
value.emptiable_rel_bound_pair()
}
}