use std::cmp::Ordering;
use std::error::Error;
use std::fmt::Display;
use std::ops::Bound;
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
use jiff::Timestamp;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::intervals::absolute::{
AbsBound,
AbsFiniteBound,
AbsFiniteBoundPos,
AbsFiniteEndBound,
AbsFiniteStartBound,
AbsStartBound,
};
use crate::intervals::meta::{BoundExtremality, BoundInclusivity, HasBoundExtremality};
use crate::intervals::ops::{BoundEq, BoundOrd, BoundOrdExtremaOps, BoundOrdering, BoundOverlapDisambiguationRuleSet};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum AbsEndBound {
Finite(AbsFiniteEndBound),
InfiniteFuture,
}
impl AbsEndBound {
#[must_use]
pub fn is_finite(&self) -> bool {
matches!(self, Self::Finite(_))
}
#[must_use]
pub fn is_infinite_future(&self) -> bool {
matches!(self, Self::InfiniteFuture)
}
#[must_use]
pub fn opposite(&self) -> Option<AbsStartBound> {
match self {
Self::Finite(finite) => Some(finite.opposite().to_start_bound()),
Self::InfiniteFuture => None,
}
}
#[must_use]
pub fn finite(self) -> Option<AbsFiniteEndBound> {
match self {
Self::Finite(finite) => Some(finite),
Self::InfiniteFuture => None,
}
}
#[must_use]
pub fn to_bound(self) -> AbsBound {
AbsBound::from(self)
}
}
impl HasBoundExtremality for AbsEndBound {
fn bound_extremality(&self) -> BoundExtremality {
BoundExtremality::End
}
}
impl PartialOrd for AbsEndBound {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AbsEndBound {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Self::InfiniteFuture, Self::InfiniteFuture) => Ordering::Equal,
(Self::InfiniteFuture, Self::Finite(_)) => Ordering::Greater,
(Self::Finite(_), Self::InfiniteFuture) => Ordering::Less,
(Self::Finite(lhs_finite_end), Self::Finite(rhs_finite_end)) => lhs_finite_end.cmp(rhs_finite_end),
}
}
}
impl BoundEq for AbsEndBound {
fn bound_eq(&self, other: &Self, rule_set: BoundOverlapDisambiguationRuleSet) -> bool {
match self {
Self::Finite(lhs_finite_start) => lhs_finite_start.bound_eq(other, rule_set),
Self::InfiniteFuture => other.is_infinite_future(),
}
}
}
impl BoundEq<AbsFiniteStartBound> for AbsEndBound {
fn bound_eq(&self, other: &AbsFiniteStartBound, rule_set: BoundOverlapDisambiguationRuleSet) -> bool {
self.finite()
.is_some_and(|finite_end| finite_end.bound_eq(other, rule_set))
}
}
impl BoundEq<AbsFiniteEndBound> for AbsEndBound {
fn bound_eq(&self, other: &AbsFiniteEndBound, rule_set: BoundOverlapDisambiguationRuleSet) -> bool {
self.finite()
.is_some_and(|finite_end| finite_end.bound_eq(other, rule_set))
}
}
impl BoundEq<AbsFiniteBound> for AbsEndBound {
fn bound_eq(&self, other: &AbsFiniteBound, rule_set: BoundOverlapDisambiguationRuleSet) -> bool {
self.finite()
.is_some_and(|finite_end| finite_end.bound_eq(other, rule_set))
}
}
impl BoundEq<AbsStartBound> for AbsEndBound {
fn bound_eq(&self, other: &AbsStartBound, rule_set: BoundOverlapDisambiguationRuleSet) -> bool {
self.finite()
.is_some_and(|finite_end| finite_end.bound_eq(other, rule_set))
}
}
impl BoundEq<AbsBound> for AbsEndBound {
fn bound_eq(&self, other: &AbsBound, rule_set: BoundOverlapDisambiguationRuleSet) -> bool {
match other {
AbsBound::Start(rhs_start) => self.bound_eq(rhs_start, rule_set),
AbsBound::End(rhs_end) => self.bound_eq(rhs_end, rule_set),
}
}
}
impl BoundOrd for AbsEndBound {
fn bound_cmp(&self, other: &Self) -> BoundOrdering {
match (self, other) {
(Self::InfiniteFuture, Self::InfiniteFuture) => BoundOrdering::Equal(None),
(Self::InfiniteFuture, Self::Finite(_)) => BoundOrdering::Greater,
(Self::Finite(_), Self::InfiniteFuture) => BoundOrdering::Less,
(Self::Finite(lhs_finite_end), Self::Finite(rhs_finite_end)) => lhs_finite_end.bound_cmp(rhs_finite_end),
}
}
}
impl BoundOrdExtremaOps for AbsEndBound {}
impl BoundOrd<AbsFiniteStartBound> for AbsEndBound {
fn bound_cmp(&self, other: &AbsFiniteStartBound) -> BoundOrdering {
match self {
Self::Finite(finite_end) => finite_end.bound_cmp(other),
Self::InfiniteFuture => BoundOrdering::Greater,
}
}
}
impl BoundOrd<AbsFiniteEndBound> for AbsEndBound {
fn bound_cmp(&self, other: &AbsFiniteEndBound) -> BoundOrdering {
match self {
Self::Finite(finite_end) => finite_end.bound_cmp(other),
Self::InfiniteFuture => BoundOrdering::Greater,
}
}
}
impl BoundOrd<AbsFiniteBound> for AbsEndBound {
fn bound_cmp(&self, other: &AbsFiniteBound) -> BoundOrdering {
match self {
Self::Finite(finite_end) => finite_end.bound_cmp(other),
Self::InfiniteFuture => BoundOrdering::Greater,
}
}
}
impl BoundOrd<AbsStartBound> for AbsEndBound {
fn bound_cmp(&self, other: &AbsStartBound) -> BoundOrdering {
match self {
Self::Finite(finite_end) => finite_end.bound_cmp(other),
Self::InfiniteFuture => BoundOrdering::Greater,
}
}
}
impl BoundOrd<AbsBound> for AbsEndBound {
fn bound_cmp(&self, other: &AbsBound) -> BoundOrdering {
match other {
AbsBound::Start(start) => self.bound_cmp(start),
AbsBound::End(end) => self.bound_cmp(end),
}
}
}
impl From<AbsFiniteEndBound> for AbsEndBound {
fn from(value: AbsFiniteEndBound) -> Self {
Self::Finite(value)
}
}
impl From<AbsFiniteBoundPos> for AbsEndBound {
fn from(value: AbsFiniteBoundPos) -> Self {
Self::Finite(AbsFiniteEndBound::new(value))
}
}
impl From<Option<Timestamp>> for AbsEndBound {
fn from(value: Option<Timestamp>) -> Self {
match value {
Some(timestamp) => Self::from(AbsFiniteBoundPos::from(timestamp)),
None => Self::InfiniteFuture,
}
}
}
impl From<Option<(Timestamp, BoundInclusivity)>> for AbsEndBound {
fn from(value: Option<(Timestamp, BoundInclusivity)>) -> Self {
match value {
Some((timestamp, inclusivity)) => Self::from(AbsFiniteBoundPos::new_with_incl(timestamp, inclusivity)),
None => Self::InfiniteFuture,
}
}
}
impl From<Bound<Timestamp>> for AbsEndBound {
fn from(bound: Bound<Timestamp>) -> Self {
match bound {
Bound::Included(time) => AbsFiniteBoundPos::new_with_incl(time, BoundInclusivity::Inclusive).to_end_bound(),
Bound::Excluded(time) => AbsFiniteBoundPos::new_with_incl(time, BoundInclusivity::Exclusive).to_end_bound(),
Bound::Unbounded => AbsEndBound::InfiniteFuture,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AbsEndBoundTryFromAbsBoundError;
impl Display for AbsEndBoundTryFromAbsBoundError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"An error occurred when trying to convert an `AbsBound` into an `AbsEndBound`"
)
}
}
impl Error for AbsEndBoundTryFromAbsBoundError {}
impl TryFrom<AbsBound> for AbsEndBound {
type Error = AbsEndBoundTryFromAbsBoundError;
fn try_from(value: AbsBound) -> Result<Self, Self::Error> {
value.end().ok_or(AbsEndBoundTryFromAbsBoundError)
}
}