use std::error::Error;
use std::fmt::Display;
use crate::intervals::meta::BoundInclusivity;
use crate::intervals::ops::{BoundOrd, BoundOrdering, BoundOverlapAmbiguity};
pub mod bound;
pub mod bound_pair;
pub mod bounded_interval;
pub mod emptiable_bound_pair;
pub mod emptiable_interval;
pub mod end_bound;
pub mod finite_bound;
pub mod finite_bound_position;
pub mod finite_end_bound;
pub mod finite_start_bound;
pub mod half_bounded_interval;
pub mod half_bounded_to_future_interval;
pub mod half_bounded_to_past_interval;
pub mod interval;
pub mod start_bound;
#[cfg(test)]
mod bound_pair_tests;
#[cfg(test)]
mod bound_tests;
#[cfg(test)]
mod bounded_interval_tests;
#[cfg(test)]
mod emptiable_bound_pair_tests;
#[cfg(test)]
mod emptiable_interval_tests;
#[cfg(test)]
mod end_bound_tests;
#[cfg(test)]
mod finite_bound_position_tests;
#[cfg(test)]
mod finite_bound_tests;
#[cfg(test)]
mod finite_end_bound_tests;
#[cfg(test)]
mod finite_start_bound_tests;
#[cfg(test)]
mod half_bounded_interval_tests;
#[cfg(test)]
mod half_bounded_to_future_interval_tests;
#[cfg(test)]
mod half_bounded_to_past_interval_tests;
#[cfg(test)]
mod interval_tests;
#[cfg(test)]
mod start_bound_tests;
#[doc(inline)]
pub use bound::RelBound;
#[doc(inline)]
pub use bound_pair::{HasRelBoundPair, RelBoundPair};
#[doc(inline)]
pub use bounded_interval::BoundedRelInterval;
#[doc(inline)]
pub use emptiable_bound_pair::{EmptiableRelBoundPair, HasEmptiableRelBoundPair};
#[doc(inline)]
pub use emptiable_interval::EmptiableRelInterval;
#[doc(inline)]
pub use end_bound::RelEndBound;
#[doc(inline)]
pub use finite_bound::RelFiniteBound;
#[doc(inline)]
pub use finite_bound_position::RelFiniteBoundPos;
#[doc(inline)]
pub use finite_end_bound::RelFiniteEndBound;
#[doc(inline)]
pub use finite_start_bound::RelFiniteStartBound;
#[doc(inline)]
pub use half_bounded_interval::HalfBoundedRelInterval;
#[doc(inline)]
pub use half_bounded_to_future_interval::HalfBoundedToFutureRelInterval;
#[doc(inline)]
pub use half_bounded_to_past_interval::HalfBoundedToPastRelInterval;
#[doc(inline)]
pub use interval::RelInterval;
#[doc(inline)]
pub use start_bound::RelStartBound;
pub fn swap_rel_finite_start_end_bounds(finite_start: &mut RelFiniteStartBound, finite_end: &mut RelFiniteEndBound) {
let RelFiniteStartBound(finite_start_pos) = finite_start;
let RelFiniteEndBound(finite_end_pos) = finite_end;
std::mem::swap(finite_start_pos, finite_end_pos);
}
pub fn swap_rel_start_end_bounds(start: &mut RelStartBound, end: &mut RelEndBound) {
match (&mut *start, &mut *end) {
(RelStartBound::InfinitePast, RelEndBound::InfiniteFuture) => {},
(RelStartBound::InfinitePast, RelEndBound::Finite(finite_end)) => {
*start = finite_end.pos().to_start_bound();
*end = RelEndBound::InfiniteFuture;
},
(RelStartBound::Finite(finite_start), RelEndBound::InfiniteFuture) => {
*end = finite_start.pos().to_end_bound();
*start = RelStartBound::InfinitePast;
},
(RelStartBound::Finite(finite_start), RelEndBound::Finite(finite_end)) => {
swap_rel_finite_start_end_bounds(finite_start, finite_end);
},
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RelStartEndBoundsCheckForIntervalCreationError {
StartPastEnd,
SameOffsetButNotDoublyInclusive,
}
impl Display for RelStartEndBoundsCheckForIntervalCreationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::StartPastEnd => write!(f, "Start bound is past the end bound"),
Self::SameOffsetButNotDoublyInclusive => write!(
f,
"Both bounds are on the same offset but don't have only inclusive bound inclusivities"
),
}
}
}
impl Error for RelStartEndBoundsCheckForIntervalCreationError {}
pub fn check_rel_finite_start_end_bounds_for_interval_creation(
start: &RelFiniteStartBound,
end: &RelFiniteEndBound,
) -> Result<(), RelStartEndBoundsCheckForIntervalCreationError> {
match start.bound_cmp(end) {
BoundOrdering::Less => Ok(()),
BoundOrdering::Equal(Some(BoundOverlapAmbiguity::StartEnd(start_incl, end_incl))) => {
if start_incl == BoundInclusivity::Inclusive && end_incl == BoundInclusivity::Inclusive {
Ok(())
} else {
Err(RelStartEndBoundsCheckForIntervalCreationError::SameOffsetButNotDoublyInclusive)
}
},
BoundOrdering::Equal(_) => unreachable!(),
BoundOrdering::Greater => Err(RelStartEndBoundsCheckForIntervalCreationError::StartPastEnd),
}
}
pub fn check_rel_start_end_bounds_for_interval_creation(
start: &RelStartBound,
end: &RelEndBound,
) -> Result<(), RelStartEndBoundsCheckForIntervalCreationError> {
match (start, end) {
(RelStartBound::InfinitePast, _) | (_, RelEndBound::InfiniteFuture) => Ok(()),
(RelStartBound::Finite(finite_start), RelEndBound::Finite(finite_end)) => {
check_rel_finite_start_end_bounds_for_interval_creation(finite_start, finite_end)
},
}
}
pub fn prepare_rel_finite_start_end_bounds_for_interval_creation(
start: &mut RelFiniteStartBound,
end: &mut RelFiniteEndBound,
) -> bool {
match check_rel_finite_start_end_bounds_for_interval_creation(start, end) {
Ok(()) => false,
Err(RelStartEndBoundsCheckForIntervalCreationError::StartPastEnd) => {
swap_rel_finite_start_end_bounds(start, end);
true
},
Err(RelStartEndBoundsCheckForIntervalCreationError::SameOffsetButNotDoublyInclusive) => {
let RelFiniteStartBound(finite_start) = start;
let RelFiniteEndBound(finite_end) = end;
finite_start.set_inclusivity(BoundInclusivity::Inclusive);
finite_end.set_inclusivity(BoundInclusivity::Inclusive);
true
},
}
}
pub fn prepare_rel_start_end_bounds_for_interval_creation(start: &mut RelStartBound, end: &mut RelEndBound) -> bool {
match check_rel_start_end_bounds_for_interval_creation(start, end) {
Ok(()) => false,
Err(RelStartEndBoundsCheckForIntervalCreationError::StartPastEnd) => {
swap_rel_start_end_bounds(start, end);
true
},
Err(RelStartEndBoundsCheckForIntervalCreationError::SameOffsetButNotDoublyInclusive) => {
if let RelStartBound::Finite(RelFiniteStartBound(finite_start_mut)) = start {
finite_start_mut.set_inclusivity(BoundInclusivity::Inclusive);
}
if let RelEndBound::Finite(RelFiniteEndBound(finite_end_mut)) = end {
finite_end_mut.set_inclusivity(BoundInclusivity::Inclusive);
}
true
},
}
}