use crate::intervals::absolute::{
AbsBoundPair,
AbsInterval,
BoundedAbsInterval,
EmptiableAbsBoundPair,
EmptiableAbsInterval,
HalfBoundedAbsInterval,
HasAbsBoundPair,
HasEmptiableAbsBoundPair,
};
use crate::intervals::meta::Interval;
use crate::intervals::ops::complement::Complementable;
use crate::intervals::ops::overlap::CanPositionOverlap;
use crate::intervals::ops::remove_overlap::{
OverlapRemovable,
OverlapRemovalNoOverlapFoundError,
OverlapRemovalResult,
};
use crate::intervals::relative::{
BoundedRelInterval,
EmptiableRelBoundPair,
EmptiableRelInterval,
HalfBoundedRelInterval,
HasEmptiableRelBoundPair,
HasRelBoundPair,
RelBoundPair,
RelInterval,
};
use crate::intervals::special::{EmptyInterval, UnboundedInterval};
use crate::ops::{ComplementResult, DifferenceResult};
pub trait Differentiable<Rhs = Self> {
type Output;
#[must_use]
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output>;
#[must_use]
fn diff_with<F>(&self, rhs: &Rhs, mut f: F) -> DifferenceResult<Self::Output>
where
F: FnMut(&Self, &Rhs) -> DifferenceResult<Self::Output>,
{
(f)(self, rhs)
}
}
impl<Rhs> Differentiable<Rhs> for AbsBoundPair
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = EmptiableAbsBoundPair;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_abs_bound_pair_with_emptiable_abs_bound_pair(self, &rhs.emptiable_abs_bound_pair())
}
}
impl<Rhs> Differentiable<Rhs> for EmptiableAbsBoundPair
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = Self;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_emptiable_abs_bound_pair(self, &rhs.emptiable_abs_bound_pair())
}
}
impl<Rhs> Differentiable<Rhs> for AbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = EmptiableAbsInterval;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_difference(Self::Output::from)
}
}
impl<Rhs> Differentiable<Rhs> for EmptiableAbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = Self;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_emptiable_abs_bound_pair(&self.emptiable_abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_difference(Self::Output::from)
}
}
impl<Rhs> Differentiable<Rhs> for BoundedAbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = EmptiableAbsInterval;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_difference(Self::Output::from)
}
}
impl<Rhs> Differentiable<Rhs> for HalfBoundedAbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = EmptiableAbsInterval;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_difference(Self::Output::from)
}
}
impl<Rhs> Differentiable<Rhs> for RelBoundPair
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = EmptiableRelBoundPair;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_rel_bound_pair_with_emptiable_rel_bound_pair(self, &rhs.emptiable_rel_bound_pair())
}
}
impl<Rhs> Differentiable<Rhs> for EmptiableRelBoundPair
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = Self;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_emptiable_rel_bound_pair(self, &rhs.emptiable_rel_bound_pair())
}
}
impl<Rhs> Differentiable<Rhs> for RelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = EmptiableRelInterval;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_difference(Self::Output::from)
}
}
impl<Rhs> Differentiable<Rhs> for EmptiableRelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = Self;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_emptiable_rel_bound_pair(&self.emptiable_rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_difference(Self::Output::from)
}
}
impl<Rhs> Differentiable<Rhs> for BoundedRelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = EmptiableRelInterval;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_difference(Self::Output::from)
}
}
impl<Rhs> Differentiable<Rhs> for HalfBoundedRelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = EmptiableRelInterval;
fn diff(&self, rhs: &Rhs) -> DifferenceResult<Self::Output> {
diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_difference(Self::Output::from)
}
}
impl Differentiable<AbsBoundPair> for UnboundedInterval {
type Output = EmptiableAbsInterval;
fn diff(&self, rhs: &AbsBoundPair) -> DifferenceResult<Self::Output> {
diff_abs_bound_pair(&self.abs_bound_pair(), &rhs.abs_bound_pair()).map_difference(Self::Output::from)
}
}
impl Differentiable<EmptiableAbsBoundPair> for UnboundedInterval {
type Output = EmptiableAbsInterval;
fn diff(&self, rhs: &EmptiableAbsBoundPair) -> DifferenceResult<Self::Output> {
diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_difference(Self::Output::from)
}
}
impl Differentiable<BoundedAbsInterval> for UnboundedInterval {
type Output = HalfBoundedAbsInterval;
fn diff(&self, rhs: &BoundedAbsInterval) -> DifferenceResult<Self::Output> {
match rhs.complement() {
ComplementResult::Single(single) => DifferenceResult::Single(single),
ComplementResult::Split(split_before, split_after) => DifferenceResult::Split(split_before, split_after),
}
}
}
impl Differentiable<HalfBoundedAbsInterval> for UnboundedInterval {
type Output = HalfBoundedAbsInterval;
fn diff(&self, rhs: &HalfBoundedAbsInterval) -> DifferenceResult<Self::Output> {
match rhs.complement() {
ComplementResult::Single(single) => DifferenceResult::Single(single),
ComplementResult::Split(split_before, split_after) => DifferenceResult::Split(split_before, split_after),
}
}
}
impl Differentiable<RelBoundPair> for UnboundedInterval {
type Output = EmptiableRelInterval;
fn diff(&self, rhs: &RelBoundPair) -> DifferenceResult<Self::Output> {
diff_rel_bound_pair(&self.rel_bound_pair(), &rhs.rel_bound_pair()).map_difference(Self::Output::from)
}
}
impl Differentiable<EmptiableRelBoundPair> for UnboundedInterval {
type Output = EmptiableRelInterval;
fn diff(&self, rhs: &EmptiableRelBoundPair) -> DifferenceResult<Self::Output> {
diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_difference(Self::Output::from)
}
}
impl Differentiable<BoundedRelInterval> for UnboundedInterval {
type Output = HalfBoundedRelInterval;
fn diff(&self, rhs: &BoundedRelInterval) -> DifferenceResult<Self::Output> {
match rhs.complement() {
ComplementResult::Single(single) => DifferenceResult::Single(single),
ComplementResult::Split(split_before, split_after) => DifferenceResult::Split(split_before, split_after),
}
}
}
impl Differentiable<HalfBoundedRelInterval> for UnboundedInterval {
type Output = HalfBoundedRelInterval;
fn diff(&self, rhs: &HalfBoundedRelInterval) -> DifferenceResult<Self::Output> {
match rhs.complement() {
ComplementResult::Single(single) => DifferenceResult::Single(single),
ComplementResult::Split(split_before, split_after) => DifferenceResult::Split(split_before, split_after),
}
}
}
impl Differentiable<UnboundedInterval> for UnboundedInterval {
type Output = EmptyInterval;
fn diff(&self, _rhs: &UnboundedInterval) -> DifferenceResult<Self::Output> {
DifferenceResult::Single(EmptyInterval)
}
}
impl Differentiable<EmptyInterval> for UnboundedInterval {
type Output = UnboundedInterval;
fn diff(&self, _rhs: &EmptyInterval) -> DifferenceResult<Self::Output> {
DifferenceResult::Single(UnboundedInterval)
}
}
impl<Rhs> Differentiable<Rhs> for EmptyInterval
where
Rhs: Interval,
{
type Output = ();
fn diff(&self, _rhs: &Rhs) -> DifferenceResult<Self::Output> {
DifferenceResult::Separate
}
}
#[must_use]
pub fn diff_abs_bound_pair(
og_bounds: &AbsBoundPair,
other_bounds: &AbsBoundPair,
) -> DifferenceResult<EmptiableAbsBoundPair> {
if !og_bounds.simple_overlaps(other_bounds) {
return DifferenceResult::Separate;
}
match og_bounds.remove_overlap(other_bounds) {
Ok(overlap_removal_res) => match overlap_removal_res {
OverlapRemovalResult::Single(single) => DifferenceResult::Single(single),
OverlapRemovalResult::Split(s1, s2) => DifferenceResult::Split(s1, s2),
},
Err(OverlapRemovalNoOverlapFoundError) => unreachable!("Overlap check already happened earlier"),
}
}
#[must_use]
pub fn diff_abs_bound_pair_with_emptiable_abs_bound_pair(
og_bounds: &AbsBoundPair,
other_bounds: &EmptiableAbsBoundPair,
) -> DifferenceResult<EmptiableAbsBoundPair> {
let EmptiableAbsBoundPair::Bound(other_bounds) = other_bounds else {
return DifferenceResult::Separate;
};
diff_abs_bound_pair(og_bounds, other_bounds)
}
#[must_use]
pub fn diff_emptiable_abs_bound_pair(
og_bounds: &EmptiableAbsBoundPair,
other_bounds: &EmptiableAbsBoundPair,
) -> DifferenceResult<EmptiableAbsBoundPair> {
let EmptiableAbsBoundPair::Bound(og_bounds) = og_bounds else {
return DifferenceResult::Separate;
};
diff_abs_bound_pair_with_emptiable_abs_bound_pair(og_bounds, other_bounds)
}
#[must_use]
pub fn diff_rel_bound_pair(
og_bounds: &RelBoundPair,
other_bounds: &RelBoundPair,
) -> DifferenceResult<EmptiableRelBoundPair> {
if !og_bounds.simple_overlaps(other_bounds) {
return DifferenceResult::Separate;
}
match og_bounds.remove_overlap(other_bounds) {
Ok(overlap_removal_res) => match overlap_removal_res {
OverlapRemovalResult::Single(single) => DifferenceResult::Single(single),
OverlapRemovalResult::Split(s1, s2) => DifferenceResult::Split(s1, s2),
},
Err(OverlapRemovalNoOverlapFoundError) => unreachable!("Overlap check already happened earlier"),
}
}
#[must_use]
pub fn diff_rel_bound_pair_with_emptiable_rel_bound_pair(
og_bounds: &RelBoundPair,
other_bounds: &EmptiableRelBoundPair,
) -> DifferenceResult<EmptiableRelBoundPair> {
let EmptiableRelBoundPair::Bound(other_bounds) = other_bounds else {
return DifferenceResult::Separate;
};
diff_rel_bound_pair(og_bounds, other_bounds)
}
#[must_use]
pub fn diff_emptiable_rel_bound_pair(
og_bounds: &EmptiableRelBoundPair,
other_bounds: &EmptiableRelBoundPair,
) -> DifferenceResult<EmptiableRelBoundPair> {
let EmptiableRelBoundPair::Bound(og_bounds) = og_bounds else {
return DifferenceResult::Separate;
};
diff_rel_bound_pair_with_emptiable_rel_bound_pair(og_bounds, other_bounds)
}