use std::cmp::Ordering;
use std::convert::Infallible;
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::intervals::absolute::{
AbsBoundPair,
AbsEndBound,
AbsFiniteEndBound,
AbsFiniteStartBound,
AbsInterval,
AbsStartBound,
BoundedAbsInterval,
EmptiableAbsBoundPair,
HalfBoundedAbsInterval,
HasEmptiableAbsBoundPair,
};
use crate::intervals::meta::{HasBoundInclusivity, Interval};
use crate::intervals::ops::bound_overlap_ambiguity::{
BoundOverlapAmbiguity,
BoundOverlapDisambiguationRuleSet,
DisambiguatedBoundOverlap,
};
use crate::intervals::relative::{
BoundedRelInterval,
EmptiableRelBoundPair,
HalfBoundedRelInterval,
HasEmptiableRelBoundPair,
RelBoundPair,
RelEndBound,
RelFiniteEndBound,
RelFiniteStartBound,
RelInterval,
RelStartBound,
};
use crate::intervals::special::{EmptyInterval, UnboundedInterval};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum OverlapPosition {
OutsideBefore,
OutsideAfter,
Outside,
EndsOnStart(BoundOverlapAmbiguity),
StartsOnEnd(BoundOverlapAmbiguity),
CrossesStart,
CrossesEnd,
Inside,
InsideAndSameStart(Option<BoundOverlapAmbiguity>),
InsideAndSameEnd(Option<BoundOverlapAmbiguity>),
Equal(Option<BoundOverlapAmbiguity>, Option<BoundOverlapAmbiguity>),
ContainsAndSameStart(Option<BoundOverlapAmbiguity>),
ContainsAndSameEnd(Option<BoundOverlapAmbiguity>),
Contains,
}
impl OverlapPosition {
#[must_use]
pub fn strip(self) -> DisambiguatedOverlapPosition {
match self {
OverlapPosition::OutsideBefore => DisambiguatedOverlapPosition::OutsideBefore,
OverlapPosition::OutsideAfter => DisambiguatedOverlapPosition::OutsideAfter,
OverlapPosition::Outside => DisambiguatedOverlapPosition::Outside,
OverlapPosition::EndsOnStart(..) => DisambiguatedOverlapPosition::EndsOnStart,
OverlapPosition::StartsOnEnd(..) => DisambiguatedOverlapPosition::StartsOnEnd,
OverlapPosition::CrossesStart => DisambiguatedOverlapPosition::CrossesStart,
OverlapPosition::CrossesEnd => DisambiguatedOverlapPosition::CrossesEnd,
OverlapPosition::Inside => DisambiguatedOverlapPosition::Inside,
OverlapPosition::InsideAndSameStart(..) => DisambiguatedOverlapPosition::InsideAndSameStart,
OverlapPosition::InsideAndSameEnd(..) => DisambiguatedOverlapPosition::InsideAndSameEnd,
OverlapPosition::Equal(..) => DisambiguatedOverlapPosition::Equal,
OverlapPosition::ContainsAndSameStart(..) => DisambiguatedOverlapPosition::ContainsAndSameStart,
OverlapPosition::ContainsAndSameEnd(..) => DisambiguatedOverlapPosition::ContainsAndSameEnd,
OverlapPosition::Contains => DisambiguatedOverlapPosition::Contains,
}
}
#[must_use]
pub fn disambiguate_using_rule_set(self, rule_set: OverlapRuleSet) -> DisambiguatedOverlapPosition {
rule_set.disambiguate(self)
}
#[must_use]
pub fn disambiguate_using<F>(self, f: F) -> DisambiguatedOverlapPosition
where
F: FnOnce(OverlapPosition) -> DisambiguatedOverlapPosition,
{
(f)(self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum DisambiguatedOverlapPosition {
OutsideBefore,
OutsideAfter,
Outside,
EndsOnStart,
StartsOnEnd,
CrossesStart,
CrossesEnd,
Inside,
InsideAndSameStart,
InsideAndSameEnd,
Equal,
ContainsAndSameStart,
ContainsAndSameEnd,
Contains,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum OverlapRuleSet {
#[default]
Strict,
Lenient,
VeryLenient,
ContinuousToFuture,
ContinuousToPast,
}
impl OverlapRuleSet {
#[must_use]
pub fn disambiguate(&self, overlap_position: OverlapPosition) -> DisambiguatedOverlapPosition {
type Bodrs = BoundOverlapDisambiguationRuleSet;
match self {
Self::Strict => overlap_position_disambiguation(overlap_position, Bodrs::Strict),
Self::ContinuousToFuture => overlap_position_disambiguation(overlap_position, Bodrs::ContinuousToFuture),
Self::ContinuousToPast => overlap_position_disambiguation(overlap_position, Bodrs::ContinuousToPast),
Self::Lenient => overlap_position_disambiguation(overlap_position, Bodrs::Lenient),
Self::VeryLenient => overlap_position_disambiguation(overlap_position, Bodrs::VeryLenient),
}
}
}
#[must_use]
pub fn overlap_position_disambiguation(
overlap_position: OverlapPosition,
bound_overlap_disambiguation_rule_set: BoundOverlapDisambiguationRuleSet,
) -> DisambiguatedOverlapPosition {
type Op = OverlapPosition;
type Dop = DisambiguatedOverlapPosition;
type Dbo = DisambiguatedBoundOverlap;
match overlap_position {
Op::Outside => Dop::Outside,
Op::OutsideBefore => Dop::OutsideBefore,
Op::OutsideAfter => Dop::OutsideAfter,
Op::EndsOnStart(ambiguity) => match ambiguity.disambiguate(bound_overlap_disambiguation_rule_set) {
Dbo::Before => Dop::CrossesStart,
Dbo::Equal => Dop::EndsOnStart,
Dbo::After => Dop::OutsideBefore,
},
Op::StartsOnEnd(ambiguity) => match ambiguity.disambiguate(bound_overlap_disambiguation_rule_set) {
Dbo::Before => Dop::OutsideAfter,
Dbo::Equal => Dop::StartsOnEnd,
Dbo::After => Dop::CrossesEnd,
},
Op::CrossesStart => Dop::CrossesStart,
Op::CrossesEnd => Dop::CrossesEnd,
Op::Inside => Dop::Inside,
Op::InsideAndSameStart(None) => Dop::InsideAndSameStart,
Op::InsideAndSameStart(Some(ambiguity)) => {
match ambiguity.disambiguate(bound_overlap_disambiguation_rule_set) {
Dbo::Before => Dop::Inside,
Dbo::Equal => Dop::InsideAndSameStart,
Dbo::After => Dop::CrossesStart,
}
},
Op::Equal(None, None) => Dop::Equal,
Op::Equal(Some(ambiguity), None) => overlap_position_bound_ambiguity_disambiguation_equal_half_bounded(
ambiguity,
bound_overlap_disambiguation_rule_set,
),
Op::Equal(None, Some(_)) => {
unreachable!(
"When there is a bound ambiguity for an equal position for comparing two half-bounded intervals, \
which produces a single bound ambiguity, the bound ambiguity is never stored in the second element \
of the `OverlapPosition::Equal` variant"
);
},
Op::Equal(Some(start_ambiguity), Some(end_ambiguity)) => {
overlap_position_bound_ambiguity_disambiguation_equal_bounded(
start_ambiguity,
end_ambiguity,
bound_overlap_disambiguation_rule_set,
)
},
Op::InsideAndSameEnd(None) => Dop::InsideAndSameEnd,
Op::InsideAndSameEnd(Some(ambiguity)) => match ambiguity.disambiguate(bound_overlap_disambiguation_rule_set) {
Dbo::Before => Dop::CrossesEnd,
Dbo::Equal => Dop::InsideAndSameEnd,
Dbo::After => Dop::Inside,
},
Op::ContainsAndSameStart(None) => Dop::ContainsAndSameStart,
Op::ContainsAndSameStart(Some(ambiguity)) => {
match ambiguity.disambiguate(bound_overlap_disambiguation_rule_set) {
Dbo::Before => Dop::CrossesEnd,
Dbo::Equal => Dop::ContainsAndSameStart,
Dbo::After => Dop::Contains,
}
},
Op::ContainsAndSameEnd(None) => Dop::ContainsAndSameEnd,
Op::ContainsAndSameEnd(Some(ambiguity)) => {
match ambiguity.disambiguate(bound_overlap_disambiguation_rule_set) {
Dbo::Before => Dop::Contains,
Dbo::Equal => Dop::ContainsAndSameEnd,
Dbo::After => Dop::CrossesStart,
}
},
Op::Contains => Dop::Contains,
}
}
#[must_use]
pub fn overlap_position_bound_ambiguity_disambiguation_equal_half_bounded(
ambiguity: BoundOverlapAmbiguity,
bound_overlap_disambiguation_rule_set: BoundOverlapDisambiguationRuleSet,
) -> DisambiguatedOverlapPosition {
type Dbo = DisambiguatedBoundOverlap;
type Dop = DisambiguatedOverlapPosition;
match ambiguity {
BoundOverlapAmbiguity::BothStarts(..) => match ambiguity.disambiguate(bound_overlap_disambiguation_rule_set) {
Dbo::Before => Dop::InsideAndSameEnd,
Dbo::Equal => Dop::Equal,
Dbo::After => Dop::ContainsAndSameEnd,
},
BoundOverlapAmbiguity::BothEnds(..) => match ambiguity.disambiguate(bound_overlap_disambiguation_rule_set) {
Dbo::Before => Dop::ContainsAndSameStart,
Dbo::Equal => Dop::Equal,
Dbo::After => Dop::InsideAndSameStart,
},
BoundOverlapAmbiguity::StartEnd(..) | BoundOverlapAmbiguity::EndStart(..) => {
unreachable!(
"When there is a bound ambiguity for an equal position for comparing two half-bounded intervals, \
which produces a single bound ambiguity, the bound ambiguity is always either BothStarts or \
BothEnds, but never StartEnd nor EndStart"
);
},
}
}
#[must_use]
pub fn overlap_position_bound_ambiguity_disambiguation_equal_bounded(
start_ambiguity: BoundOverlapAmbiguity,
end_ambiguity: BoundOverlapAmbiguity,
bound_overlap_disambiguation_rule_set: BoundOverlapDisambiguationRuleSet,
) -> DisambiguatedOverlapPosition {
type Dbo = DisambiguatedBoundOverlap;
type Dop = DisambiguatedOverlapPosition;
let disambiguated_start_bound = start_ambiguity.disambiguate(bound_overlap_disambiguation_rule_set);
let disambiguated_end_bound = end_ambiguity.disambiguate(bound_overlap_disambiguation_rule_set);
match (disambiguated_start_bound, disambiguated_end_bound) {
(Dbo::Before, Dbo::Before) => Dop::CrossesEnd,
(Dbo::Before, Dbo::Equal) => Dop::InsideAndSameEnd,
(Dbo::Before, Dbo::After) => Dop::Inside,
(Dbo::Equal, Dbo::Before) => Dop::ContainsAndSameStart,
(Dbo::Equal, Dbo::Equal) => Dop::Equal,
(Dbo::Equal, Dbo::After) => Dop::InsideAndSameStart,
(Dbo::After, Dbo::Before) => Dop::Contains,
(Dbo::After, Dbo::Equal) => Dop::ContainsAndSameEnd,
(Dbo::After, Dbo::After) => Dop::CrossesStart,
}
}
pub const DEFAULT_OVERLAP_RULES: [OverlapRule; 1] = [OverlapRule::AllowAdjacency];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum OverlapRule {
AllowAdjacency,
AllowPastAdjacency,
AllowFutureAdjacency,
DenyAdjacency,
DenyPastAdjacency,
DenyFutureAdjacency,
}
impl OverlapRule {
#[must_use]
pub fn counts_as_overlap(&self, running: bool, disambiguated_pos: DisambiguatedOverlapPosition) -> bool {
match self {
Self::AllowAdjacency => allow_adjacency_overlap_rule_counts_as_overlap(running, disambiguated_pos),
Self::AllowPastAdjacency => allow_past_adjacency_overlap_rule_counts_as_overlap(running, disambiguated_pos),
Self::AllowFutureAdjacency => {
allow_future_adjacency_overlap_rule_counts_as_overlap(running, disambiguated_pos)
},
Self::DenyAdjacency => deny_adjacency_overlap_rule_counts_as_overlap(running, disambiguated_pos),
Self::DenyPastAdjacency => deny_past_adjacency_overlap_rule_counts_as_overlap(running, disambiguated_pos),
Self::DenyFutureAdjacency => {
deny_future_adjacency_overlap_rule_counts_as_overlap(running, disambiguated_pos)
},
}
}
}
#[must_use]
pub fn check_overlap_rules<'a, RI>(disambiguated_overlap_position: DisambiguatedOverlapPosition, rules: RI) -> bool
where
RI: IntoIterator<Item = &'a OverlapRule>,
{
let common = matches!(
disambiguated_overlap_position,
DisambiguatedOverlapPosition::CrossesStart
| DisambiguatedOverlapPosition::CrossesEnd
| DisambiguatedOverlapPosition::Inside
| DisambiguatedOverlapPosition::InsideAndSameStart
| DisambiguatedOverlapPosition::InsideAndSameEnd
| DisambiguatedOverlapPosition::Equal
| DisambiguatedOverlapPosition::ContainsAndSameStart
| DisambiguatedOverlapPosition::ContainsAndSameEnd
| DisambiguatedOverlapPosition::Contains,
);
rules.into_iter().fold(common, |is_overlapping, rule| {
rule.counts_as_overlap(is_overlapping, disambiguated_overlap_position)
})
}
#[must_use]
pub fn allow_adjacency_overlap_rule_counts_as_overlap(
running: bool,
disambiguated_pos: DisambiguatedOverlapPosition,
) -> bool {
running
|| matches!(
disambiguated_pos,
DisambiguatedOverlapPosition::EndsOnStart | DisambiguatedOverlapPosition::StartsOnEnd
)
}
#[must_use]
pub fn allow_past_adjacency_overlap_rule_counts_as_overlap(
running: bool,
disambiguated_pos: DisambiguatedOverlapPosition,
) -> bool {
running || matches!(disambiguated_pos, DisambiguatedOverlapPosition::EndsOnStart)
}
#[must_use]
pub fn allow_future_adjacency_overlap_rule_counts_as_overlap(
running: bool,
disambiguated_pos: DisambiguatedOverlapPosition,
) -> bool {
running || matches!(disambiguated_pos, DisambiguatedOverlapPosition::StartsOnEnd)
}
#[must_use]
pub fn deny_adjacency_overlap_rule_counts_as_overlap(
running: bool,
disambiguated_pos: DisambiguatedOverlapPosition,
) -> bool {
running
&& !matches!(
disambiguated_pos,
DisambiguatedOverlapPosition::EndsOnStart | DisambiguatedOverlapPosition::StartsOnEnd,
)
}
#[must_use]
pub fn deny_past_adjacency_overlap_rule_counts_as_overlap(
running: bool,
disambiguated_pos: DisambiguatedOverlapPosition,
) -> bool {
running && !matches!(disambiguated_pos, DisambiguatedOverlapPosition::EndsOnStart)
}
#[must_use]
pub fn deny_future_adjacency_overlap_rule_counts_as_overlap(
running: bool,
disambiguated_pos: DisambiguatedOverlapPosition,
) -> bool {
running && !matches!(disambiguated_pos, DisambiguatedOverlapPosition::StartsOnEnd)
}
pub trait CanPositionOverlap<Rhs = Self> {
type Error;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error>;
fn disambiguated_overlap_position(
&self,
rhs: &Rhs,
rule_set: OverlapRuleSet,
) -> Result<DisambiguatedOverlapPosition, Self::Error> {
self.overlap_position(rhs)
.map(|overlap_position| rule_set.disambiguate(overlap_position))
}
#[must_use]
fn simple_overlaps(&self, rhs: &Rhs) -> bool {
self.overlaps(rhs, OverlapRuleSet::default(), &DEFAULT_OVERLAP_RULES)
}
#[must_use]
fn overlaps<'a, RI>(&self, rhs: &Rhs, rule_set: OverlapRuleSet, rules: RI) -> bool
where
RI: IntoIterator<Item = &'a OverlapRule>,
{
self.disambiguated_overlap_position(rhs, rule_set)
.is_ok_and(|disambiguated_overlap_position| check_overlap_rules(disambiguated_overlap_position, rules))
}
#[must_use]
fn overlaps_using<F>(&self, rhs: &Rhs, f: F) -> bool
where
F: FnOnce(OverlapPosition) -> bool,
{
self.overlap_position(rhs).is_ok_and(f)
}
#[must_use]
fn overlaps_using_disambiguated<F>(&self, rhs: &Rhs, rule_set: OverlapRuleSet, f: F) -> bool
where
F: FnOnce(DisambiguatedOverlapPosition) -> bool,
{
self.disambiguated_overlap_position(rhs, rule_set).is_ok_and(f)
}
}
impl<Rhs> CanPositionOverlap<Rhs> for AbsBoundPair
where
Rhs: HasEmptiableAbsBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for EmptiableAbsBoundPair
where
Rhs: HasEmptiableAbsBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for AbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for BoundedAbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for HalfBoundedAbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for RelBoundPair
where
Rhs: HasEmptiableRelBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_rel_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for EmptiableRelBoundPair
where
Rhs: HasEmptiableRelBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_rel_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for RelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_rel_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for BoundedRelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_rel_bound_pair(self, rhs))
}
}
impl<Rhs> CanPositionOverlap<Rhs> for HalfBoundedRelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Error = Infallible;
fn overlap_position(&self, rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_rel_bound_pair(self, rhs))
}
}
impl CanPositionOverlap<AbsBoundPair> for UnboundedInterval {
type Error = Infallible;
fn overlap_position(&self, rhs: &AbsBoundPair) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl CanPositionOverlap<EmptiableAbsBoundPair> for UnboundedInterval {
type Error = Infallible;
fn overlap_position(&self, rhs: &EmptiableAbsBoundPair) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl CanPositionOverlap<AbsInterval> for UnboundedInterval {
type Error = Infallible;
fn overlap_position(&self, rhs: &AbsInterval) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl CanPositionOverlap<BoundedAbsInterval> for UnboundedInterval {
type Error = Infallible;
fn overlap_position(&self, rhs: &BoundedAbsInterval) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl CanPositionOverlap<HalfBoundedAbsInterval> for UnboundedInterval {
type Error = Infallible;
fn overlap_position(&self, rhs: &HalfBoundedAbsInterval) -> Result<OverlapPosition, Self::Error> {
Ok(overlap_position_emptiable_abs_bound_pair(self, rhs))
}
}
impl CanPositionOverlap<UnboundedInterval> for UnboundedInterval {
type Error = Infallible;
fn overlap_position(&self, _rhs: &UnboundedInterval) -> Result<OverlapPosition, Self::Error> {
Ok(OverlapPosition::Equal(None, None))
}
}
impl CanPositionOverlap<EmptyInterval> for UnboundedInterval {
type Error = Infallible;
fn overlap_position(&self, _rhs: &EmptyInterval) -> Result<OverlapPosition, Self::Error> {
Ok(OverlapPosition::Outside)
}
}
impl<Rhs> CanPositionOverlap<Rhs> for EmptyInterval
where
Rhs: Interval,
{
type Error = Infallible;
fn overlap_position(&self, _rhs: &Rhs) -> Result<OverlapPosition, Self::Error> {
Ok(OverlapPosition::Outside)
}
}
#[must_use]
pub fn overlap_position_abs_bound_pair(og: &AbsBoundPair, other: &AbsBoundPair) -> OverlapPosition {
type Sb = AbsStartBound;
type Eb = AbsEndBound;
type Op = OverlapPosition;
match ((og.start(), og.end()), (other.start(), other.end())) {
((Sb::InfinitePast, Eb::InfiniteFuture), (Sb::InfinitePast, Eb::InfiniteFuture)) => Op::Equal(None, None),
((Sb::InfinitePast, Eb::InfiniteFuture), (Sb::InfinitePast, Eb::Finite(..))) => Op::ContainsAndSameStart(None),
((Sb::InfinitePast, Eb::InfiniteFuture), (Sb::Finite(..), Eb::InfiniteFuture)) => Op::ContainsAndSameEnd(None),
((Sb::InfinitePast, Eb::InfiniteFuture), _) => Op::Contains,
((Sb::InfinitePast, Eb::Finite(..)), (Sb::InfinitePast, Eb::InfiniteFuture)) => Op::InsideAndSameStart(None),
((Sb::Finite(..), Eb::InfiniteFuture), (Sb::InfinitePast, Eb::InfiniteFuture)) => Op::InsideAndSameEnd(None),
(_, (Sb::InfinitePast, Eb::InfiniteFuture)) => Op::Inside,
((Sb::InfinitePast, Eb::Finite(og_end)), (Sb::InfinitePast, Eb::Finite(other_end))) => {
match og_end.pos().time().cmp(&other_end.pos().time()) {
Ordering::Less => Op::InsideAndSameStart(None),
Ordering::Equal => Op::Equal(
Some(BoundOverlapAmbiguity::BothEnds(
og_end.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
None,
),
Ordering::Greater => Op::ContainsAndSameStart(None),
}
},
((Sb::Finite(og_start), Eb::InfiniteFuture), (Sb::Finite(other_start), Eb::InfiniteFuture)) => {
match og_start.pos().time().cmp(&other_start.pos().time()) {
Ordering::Less => Op::ContainsAndSameEnd(None),
Ordering::Equal => Op::Equal(
Some(BoundOverlapAmbiguity::BothStarts(
og_start.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
None,
),
Ordering::Greater => Op::InsideAndSameEnd(None),
}
},
((Sb::InfinitePast, Eb::Finite(og_end)), (Sb::Finite(other_start), Eb::InfiniteFuture)) => {
match og_end.pos().time().cmp(&other_start.pos().time()) {
Ordering::Less => Op::OutsideBefore,
Ordering::Equal => Op::EndsOnStart(BoundOverlapAmbiguity::EndStart(
og_end.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
Ordering::Greater => Op::CrossesStart,
}
},
((Sb::Finite(og_start), Eb::InfiniteFuture), (Sb::InfinitePast, Eb::Finite(other_end))) => {
match og_start.pos().time().cmp(&other_end.pos().time()) {
Ordering::Less => Op::CrossesStart,
Ordering::Equal => Op::StartsOnEnd(BoundOverlapAmbiguity::StartEnd(
og_start.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
Ordering::Greater => Op::OutsideAfter,
}
},
((Sb::InfinitePast, Eb::Finite(ref ref_bound)), (Sb::Finite(ref other_start), Eb::Finite(ref other_end))) => {
overlap_position_abs_half_bounded_past_bounded(ref_bound, other_start, other_end)
},
((Sb::Finite(ref ref_bound), Eb::InfiniteFuture), (Sb::Finite(ref other_start), Eb::Finite(ref other_end))) => {
overlap_position_abs_half_bounded_future_bounded(ref_bound, other_start, other_end)
},
((Sb::Finite(ref og_start), Eb::Finite(ref og_end)), (Sb::InfinitePast, Eb::Finite(ref ref_bound))) => {
overlap_position_abs_bounded_half_bounded_past(og_start, og_end, ref_bound)
},
((Sb::Finite(ref og_start), Eb::Finite(ref og_end)), (Sb::Finite(ref ref_bound), Eb::InfiniteFuture)) => {
overlap_position_abs_bounded_half_bounded_future(og_start, og_end, ref_bound)
},
(
(Sb::Finite(ref og_start), Eb::Finite(ref og_end)),
(Sb::Finite(ref other_start), Eb::Finite(ref other_end)),
) => overlap_position_abs_bounded_pair(og_start, og_end, other_start, other_end),
}
}
#[must_use]
pub fn overlap_position_abs_half_bounded_past_bounded(
ref_bound: &AbsFiniteEndBound,
other_start: &AbsFiniteStartBound,
other_end: &AbsFiniteEndBound,
) -> OverlapPosition {
match (
ref_bound.pos().time().cmp(&other_start.pos().time()),
ref_bound.pos().time().cmp(&other_end.pos().time()),
) {
(Ordering::Less, _) => OverlapPosition::OutsideBefore,
(Ordering::Equal, _) => OverlapPosition::EndsOnStart(BoundOverlapAmbiguity::EndStart(
ref_bound.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
(Ordering::Greater, Ordering::Less) => OverlapPosition::CrossesStart,
(_, Ordering::Equal) => OverlapPosition::ContainsAndSameEnd(Some(BoundOverlapAmbiguity::BothEnds(
ref_bound.pos().inclusivity(),
other_end.pos().inclusivity(),
))),
(_, Ordering::Greater) => OverlapPosition::Contains,
}
}
#[must_use]
pub fn overlap_position_abs_half_bounded_future_bounded(
ref_bound: &AbsFiniteStartBound,
other_start: &AbsFiniteStartBound,
other_end: &AbsFiniteEndBound,
) -> OverlapPosition {
match (
ref_bound.pos().time().cmp(&other_start.pos().time()),
ref_bound.pos().time().cmp(&other_end.pos().time()),
) {
(Ordering::Less, _) => OverlapPosition::Contains,
(Ordering::Equal, _) => OverlapPosition::ContainsAndSameStart(Some(BoundOverlapAmbiguity::BothStarts(
ref_bound.pos().inclusivity(),
other_start.pos().inclusivity(),
))),
(Ordering::Greater, Ordering::Less) => OverlapPosition::CrossesEnd,
(_, Ordering::Equal) => OverlapPosition::StartsOnEnd(BoundOverlapAmbiguity::StartEnd(
ref_bound.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
(_, Ordering::Greater) => OverlapPosition::OutsideAfter,
}
}
#[must_use]
pub fn overlap_position_abs_bounded_half_bounded_past(
og_start: &AbsFiniteStartBound,
og_end: &AbsFiniteEndBound,
ref_bound: &AbsFiniteEndBound,
) -> OverlapPosition {
match (
ref_bound.pos().time().cmp(&og_start.pos().time()),
ref_bound.pos().time().cmp(&og_end.pos().time()),
) {
(Ordering::Less, _) => OverlapPosition::OutsideAfter,
(Ordering::Equal, _) => OverlapPosition::StartsOnEnd(BoundOverlapAmbiguity::StartEnd(
og_start.pos().inclusivity(),
ref_bound.pos().inclusivity(),
)),
(Ordering::Greater, Ordering::Less) => OverlapPosition::CrossesEnd,
(_, Ordering::Equal) => OverlapPosition::InsideAndSameEnd(Some(BoundOverlapAmbiguity::BothEnds(
og_end.pos().inclusivity(),
ref_bound.pos().inclusivity(),
))),
(_, Ordering::Greater) => OverlapPosition::Inside,
}
}
#[must_use]
pub fn overlap_position_abs_bounded_half_bounded_future(
og_start: &AbsFiniteStartBound,
og_end: &AbsFiniteEndBound,
ref_bound: &AbsFiniteStartBound,
) -> OverlapPosition {
match (
ref_bound.pos().time().cmp(&og_start.pos().time()),
ref_bound.pos().time().cmp(&og_end.pos().time()),
) {
(Ordering::Less, _) => OverlapPosition::Inside,
(Ordering::Equal, _) => OverlapPosition::InsideAndSameStart(Some(BoundOverlapAmbiguity::BothStarts(
og_start.pos().inclusivity(),
ref_bound.pos().inclusivity(),
))),
(Ordering::Greater, Ordering::Less) => OverlapPosition::CrossesStart,
(_, Ordering::Equal) => OverlapPosition::EndsOnStart(BoundOverlapAmbiguity::EndStart(
og_end.pos().inclusivity(),
ref_bound.pos().inclusivity(),
)),
(_, Ordering::Greater) => OverlapPosition::OutsideBefore,
}
}
#[must_use]
pub fn overlap_position_abs_bounded_pair(
og_start: &AbsFiniteStartBound,
og_end: &AbsFiniteEndBound,
other_start: &AbsFiniteStartBound,
other_end: &AbsFiniteEndBound,
) -> OverlapPosition {
let og_start_cmp = (
og_start.pos().time().cmp(&other_start.pos().time()),
og_start.pos().time().cmp(&other_end.pos().time()),
);
let og_end_cmp = (
og_end.pos().time().cmp(&other_start.pos().time()),
og_end.pos().time().cmp(&other_end.pos().time()),
);
match (og_start_cmp, og_end_cmp) {
(_, (Ordering::Less, _)) => OverlapPosition::OutsideBefore,
((_, Ordering::Greater), _) => OverlapPosition::OutsideAfter,
(_, (Ordering::Equal, _)) => OverlapPosition::EndsOnStart(BoundOverlapAmbiguity::EndStart(
og_end.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
((_, Ordering::Equal), _) => OverlapPosition::StartsOnEnd(BoundOverlapAmbiguity::StartEnd(
og_start.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
((Ordering::Less, _), (Ordering::Greater, Ordering::Less)) => OverlapPosition::CrossesStart,
((Ordering::Greater, Ordering::Less), (_, Ordering::Greater)) => OverlapPosition::CrossesEnd,
((Ordering::Greater, _), (_, Ordering::Less)) => OverlapPosition::Inside,
((Ordering::Equal, _), (_, Ordering::Less)) => OverlapPosition::InsideAndSameStart(Some(
BoundOverlapAmbiguity::BothStarts(og_start.pos().inclusivity(), other_start.pos().inclusivity()),
)),
((Ordering::Greater, _), (_, Ordering::Equal)) => OverlapPosition::InsideAndSameEnd(Some(
BoundOverlapAmbiguity::BothEnds(og_end.pos().inclusivity(), other_end.pos().inclusivity()),
)),
((Ordering::Equal, _), (_, Ordering::Equal)) => OverlapPosition::Equal(
Some(BoundOverlapAmbiguity::BothStarts(
og_start.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
Some(BoundOverlapAmbiguity::BothEnds(
og_end.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
),
((Ordering::Equal, _), (_, Ordering::Greater)) => OverlapPosition::ContainsAndSameStart(Some(
BoundOverlapAmbiguity::BothStarts(og_start.pos().inclusivity(), other_start.pos().inclusivity()),
)),
((Ordering::Less, _), (_, Ordering::Equal)) => OverlapPosition::ContainsAndSameEnd(Some(
BoundOverlapAmbiguity::BothEnds(og_end.pos().inclusivity(), other_end.pos().inclusivity()),
)),
((Ordering::Less, _), (_, Ordering::Greater)) => OverlapPosition::Contains,
}
}
#[must_use]
pub fn overlap_position_emptiable_abs_bound_pair<T, U>(og: &T, other: &U) -> OverlapPosition
where
T: HasEmptiableAbsBoundPair,
U: HasEmptiableAbsBoundPair,
{
match (og.emptiable_abs_bound_pair(), other.emptiable_abs_bound_pair()) {
(_, EmptiableAbsBoundPair::Empty) | (EmptiableAbsBoundPair::Empty, _) => OverlapPosition::Outside,
(EmptiableAbsBoundPair::Bound(ref og_bounds), EmptiableAbsBoundPair::Bound(ref other_bounds)) => {
overlap_position_abs_bound_pair(og_bounds, other_bounds)
},
}
}
#[must_use]
pub fn overlap_position_rel_bound_pair(og: &RelBoundPair, other: &RelBoundPair) -> OverlapPosition {
type Sb = RelStartBound;
type Eb = RelEndBound;
type Op = OverlapPosition;
match ((og.start(), og.end()), (other.start(), other.end())) {
((Sb::InfinitePast, Eb::InfiniteFuture), (Sb::InfinitePast, Eb::InfiniteFuture)) => Op::Equal(None, None),
((Sb::InfinitePast, Eb::InfiniteFuture), (Sb::InfinitePast, Eb::Finite(..))) => Op::ContainsAndSameStart(None),
((Sb::InfinitePast, Eb::InfiniteFuture), (Sb::Finite(..), Eb::InfiniteFuture)) => Op::ContainsAndSameEnd(None),
((Sb::InfinitePast, Eb::InfiniteFuture), _) => Op::Contains,
((Sb::InfinitePast, Eb::Finite(..)), (Sb::InfinitePast, Eb::InfiniteFuture)) => Op::InsideAndSameStart(None),
((Sb::Finite(..), Eb::InfiniteFuture), (Sb::InfinitePast, Eb::InfiniteFuture)) => Op::InsideAndSameEnd(None),
(_, (Sb::InfinitePast, Eb::InfiniteFuture)) => Op::Inside,
((Sb::InfinitePast, Eb::Finite(og_end)), (Sb::InfinitePast, Eb::Finite(other_end))) => {
match og_end.pos().offset().cmp(&other_end.pos().offset()) {
Ordering::Less => Op::InsideAndSameStart(None),
Ordering::Equal => Op::Equal(
Some(BoundOverlapAmbiguity::BothEnds(
og_end.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
None,
),
Ordering::Greater => Op::ContainsAndSameStart(None),
}
},
((Sb::Finite(og_start), Eb::InfiniteFuture), (Sb::Finite(other_start), Eb::InfiniteFuture)) => {
match og_start.pos().offset().cmp(&other_start.pos().offset()) {
Ordering::Less => Op::ContainsAndSameEnd(None),
Ordering::Equal => Op::Equal(
Some(BoundOverlapAmbiguity::BothStarts(
og_start.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
None,
),
Ordering::Greater => Op::InsideAndSameEnd(None),
}
},
((Sb::InfinitePast, Eb::Finite(og_end)), (Sb::Finite(other_start), Eb::InfiniteFuture)) => {
match og_end.pos().offset().cmp(&other_start.pos().offset()) {
Ordering::Less => Op::OutsideBefore,
Ordering::Equal => Op::EndsOnStart(BoundOverlapAmbiguity::EndStart(
og_end.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
Ordering::Greater => Op::CrossesStart,
}
},
((Sb::Finite(og_start), Eb::InfiniteFuture), (Sb::InfinitePast, Eb::Finite(other_end))) => {
match og_start.pos().offset().cmp(&other_end.pos().offset()) {
Ordering::Less => Op::CrossesStart,
Ordering::Equal => Op::StartsOnEnd(BoundOverlapAmbiguity::StartEnd(
og_start.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
Ordering::Greater => Op::OutsideAfter,
}
},
((Sb::InfinitePast, Eb::Finite(ref ref_bound)), (Sb::Finite(ref other_start), Eb::Finite(ref other_end))) => {
overlap_position_rel_half_bounded_past_bounded(ref_bound, other_start, other_end)
},
((Sb::Finite(ref ref_bound), Eb::InfiniteFuture), (Sb::Finite(ref other_start), Eb::Finite(ref other_end))) => {
overlap_position_rel_half_bounded_future_bounded(ref_bound, other_start, other_end)
},
((Sb::Finite(ref og_start), Eb::Finite(ref og_end)), (Sb::InfinitePast, Eb::Finite(ref ref_bound))) => {
overlap_position_rel_bounded_half_bounded_past(og_start, og_end, ref_bound)
},
((Sb::Finite(ref og_start), Eb::Finite(ref og_end)), (Sb::Finite(ref ref_bound), Eb::InfiniteFuture)) => {
overlap_position_rel_bounded_half_bounded_future(og_start, og_end, ref_bound)
},
(
(Sb::Finite(ref og_start), Eb::Finite(ref og_end)),
(Sb::Finite(ref other_start), Eb::Finite(ref other_end)),
) => overlap_position_rel_bounded_pair(og_start, og_end, other_start, other_end),
}
}
#[must_use]
pub fn overlap_position_rel_half_bounded_past_bounded(
ref_bound: &RelFiniteEndBound,
other_start: &RelFiniteStartBound,
other_end: &RelFiniteEndBound,
) -> OverlapPosition {
match (
ref_bound.pos().offset().cmp(&other_start.pos().offset()),
ref_bound.pos().offset().cmp(&other_end.pos().offset()),
) {
(Ordering::Less, _) => OverlapPosition::OutsideBefore,
(Ordering::Equal, _) => OverlapPosition::EndsOnStart(BoundOverlapAmbiguity::EndStart(
ref_bound.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
(Ordering::Greater, Ordering::Less) => OverlapPosition::CrossesStart,
(_, Ordering::Equal) => OverlapPosition::ContainsAndSameEnd(Some(BoundOverlapAmbiguity::BothEnds(
ref_bound.pos().inclusivity(),
other_end.pos().inclusivity(),
))),
(_, Ordering::Greater) => OverlapPosition::Contains,
}
}
#[must_use]
pub fn overlap_position_rel_half_bounded_future_bounded(
ref_bound: &RelFiniteStartBound,
other_start: &RelFiniteStartBound,
other_end: &RelFiniteEndBound,
) -> OverlapPosition {
match (
ref_bound.pos().offset().cmp(&other_start.pos().offset()),
ref_bound.pos().offset().cmp(&other_end.pos().offset()),
) {
(Ordering::Less, _) => OverlapPosition::Contains,
(Ordering::Equal, _) => OverlapPosition::ContainsAndSameStart(Some(BoundOverlapAmbiguity::BothStarts(
ref_bound.pos().inclusivity(),
other_start.pos().inclusivity(),
))),
(Ordering::Greater, Ordering::Less) => OverlapPosition::CrossesEnd,
(_, Ordering::Equal) => OverlapPosition::StartsOnEnd(BoundOverlapAmbiguity::StartEnd(
ref_bound.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
(_, Ordering::Greater) => OverlapPosition::OutsideAfter,
}
}
#[must_use]
pub fn overlap_position_rel_bounded_half_bounded_past(
og_start: &RelFiniteStartBound,
og_end: &RelFiniteEndBound,
ref_bound: &RelFiniteEndBound,
) -> OverlapPosition {
match (
ref_bound.pos().offset().cmp(&og_start.pos().offset()),
ref_bound.pos().offset().cmp(&og_end.pos().offset()),
) {
(Ordering::Less, _) => OverlapPosition::OutsideAfter,
(Ordering::Equal, _) => OverlapPosition::StartsOnEnd(BoundOverlapAmbiguity::StartEnd(
og_start.pos().inclusivity(),
ref_bound.pos().inclusivity(),
)),
(Ordering::Greater, Ordering::Less) => OverlapPosition::CrossesEnd,
(_, Ordering::Equal) => OverlapPosition::InsideAndSameEnd(Some(BoundOverlapAmbiguity::BothEnds(
og_end.pos().inclusivity(),
ref_bound.pos().inclusivity(),
))),
(_, Ordering::Greater) => OverlapPosition::Inside,
}
}
#[must_use]
pub fn overlap_position_rel_bounded_half_bounded_future(
og_start: &RelFiniteStartBound,
og_end: &RelFiniteEndBound,
ref_bound: &RelFiniteStartBound,
) -> OverlapPosition {
match (
ref_bound.pos().offset().cmp(&og_start.pos().offset()),
ref_bound.pos().offset().cmp(&og_end.pos().offset()),
) {
(Ordering::Less, _) => OverlapPosition::Inside,
(Ordering::Equal, _) => OverlapPosition::InsideAndSameStart(Some(BoundOverlapAmbiguity::BothStarts(
og_start.pos().inclusivity(),
ref_bound.pos().inclusivity(),
))),
(Ordering::Greater, Ordering::Less) => OverlapPosition::CrossesStart,
(_, Ordering::Equal) => OverlapPosition::EndsOnStart(BoundOverlapAmbiguity::EndStart(
og_end.pos().inclusivity(),
ref_bound.pos().inclusivity(),
)),
(_, Ordering::Greater) => OverlapPosition::OutsideBefore,
}
}
#[must_use]
pub fn overlap_position_rel_bounded_pair(
og_start: &RelFiniteStartBound,
og_end: &RelFiniteEndBound,
other_start: &RelFiniteStartBound,
other_end: &RelFiniteEndBound,
) -> OverlapPosition {
let og_start_cmp = (
og_start.pos().offset().cmp(&other_start.pos().offset()),
og_start.pos().offset().cmp(&other_end.pos().offset()),
);
let og_end_cmp = (
og_end.pos().offset().cmp(&other_start.pos().offset()),
og_end.pos().offset().cmp(&other_end.pos().offset()),
);
match (og_start_cmp, og_end_cmp) {
(_, (Ordering::Less, _)) => OverlapPosition::OutsideBefore,
((_, Ordering::Greater), _) => OverlapPosition::OutsideAfter,
(_, (Ordering::Equal, _)) => OverlapPosition::EndsOnStart(BoundOverlapAmbiguity::EndStart(
og_end.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
((_, Ordering::Equal), _) => OverlapPosition::StartsOnEnd(BoundOverlapAmbiguity::StartEnd(
og_start.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
((Ordering::Less, _), (Ordering::Greater, Ordering::Less)) => OverlapPosition::CrossesStart,
((Ordering::Greater, Ordering::Less), (_, Ordering::Greater)) => OverlapPosition::CrossesEnd,
((Ordering::Greater, _), (_, Ordering::Less)) => OverlapPosition::Inside,
((Ordering::Equal, _), (_, Ordering::Less)) => OverlapPosition::InsideAndSameStart(Some(
BoundOverlapAmbiguity::BothStarts(og_start.pos().inclusivity(), other_start.pos().inclusivity()),
)),
((Ordering::Greater, _), (_, Ordering::Equal)) => OverlapPosition::InsideAndSameEnd(Some(
BoundOverlapAmbiguity::BothEnds(og_end.pos().inclusivity(), other_end.pos().inclusivity()),
)),
((Ordering::Equal, _), (_, Ordering::Equal)) => OverlapPosition::Equal(
Some(BoundOverlapAmbiguity::BothStarts(
og_start.pos().inclusivity(),
other_start.pos().inclusivity(),
)),
Some(BoundOverlapAmbiguity::BothEnds(
og_end.pos().inclusivity(),
other_end.pos().inclusivity(),
)),
),
((Ordering::Equal, _), (_, Ordering::Greater)) => OverlapPosition::ContainsAndSameStart(Some(
BoundOverlapAmbiguity::BothStarts(og_start.pos().inclusivity(), other_start.pos().inclusivity()),
)),
((Ordering::Less, _), (_, Ordering::Equal)) => OverlapPosition::ContainsAndSameEnd(Some(
BoundOverlapAmbiguity::BothEnds(og_end.pos().inclusivity(), other_end.pos().inclusivity()),
)),
((Ordering::Less, _), (_, Ordering::Greater)) => OverlapPosition::Contains,
}
}
#[must_use]
pub fn overlap_position_emptiable_rel_bound_pair<T, U>(og: &T, other: &U) -> OverlapPosition
where
T: HasEmptiableRelBoundPair,
U: HasEmptiableRelBoundPair,
{
match (og.emptiable_rel_bound_pair(), other.emptiable_rel_bound_pair()) {
(_, EmptiableRelBoundPair::Empty) | (EmptiableRelBoundPair::Empty, _) => OverlapPosition::Outside,
(EmptiableRelBoundPair::Bound(ref og_bounds), EmptiableRelBoundPair::Bound(ref other_bounds)) => {
overlap_position_rel_bound_pair(og_bounds, other_bounds)
},
}
}