range_bound_cmp 0.1.0

Comparison operations between primitive `Bound` values
Documentation
use std::fmt::Debug;
use std::ops::{Bound, RangeBounds};

use crate::error::RangeBoundError;
use crate::lower::LowerBound;
use crate::upper::UpperBound;

/// A pair of range `Bound` types for comparison operations.
#[derive(Debug, Clone, Copy, Hash)]
pub struct OrdRange<T> {
    pub start: LowerBound<T>,
    pub end: UpperBound<T>,
}

impl<T: Clone + Copy> OrdRange<T> {
    /// Create a new `OrdRange` from the given ranbe bounds.
    pub fn new(range_bounds: impl RangeBounds<T>) -> Self {
        // Temporary while `IntoBounds` is unstable.
        let start = LowerBound(range_bounds.start_bound().cloned());
        let end = UpperBound(range_bounds.end_bound().cloned());

        OrdRange { start, end }
    }

    /// Take the inner `Bound` tuple.
    pub fn take(self) -> (Bound<T>, Bound<T>) {
        (self.start.0, self.end.0)
    }
}

impl<T> TryFrom<(LowerBound<T>, UpperBound<T>)> for OrdRange<T> {
    type Error = RangeBoundError;

    fn try_from(value: (LowerBound<T>, UpperBound<T>)) -> Result<Self, Self::Error> {
        Ok(OrdRange {
            start: value.0,
            end: value.1,
        })
    }
}

impl<T> TryFrom<(LowerBound<T>, LowerBound<T>)> for OrdRange<T>
where
    LowerBound<T>: TryInto<UpperBound<T>>,
    T: Clone + Copy,
{
    type Error = <LowerBound<T> as TryInto<UpperBound<T>>>::Error;

    fn try_from((lower, upper): (LowerBound<T>, LowerBound<T>)) -> Result<Self, Self::Error> {
        Ok(OrdRange {
            start: lower,
            end: upper.try_into()?,
        })
    }
}

impl<T> TryFrom<(UpperBound<T>, UpperBound<T>)> for OrdRange<T>
where
    UpperBound<T>: TryInto<LowerBound<T>>,
    T: Clone + Copy,
{
    type Error = <UpperBound<T> as TryInto<LowerBound<T>>>::Error;

    fn try_from((lower, upper): (UpperBound<T>, UpperBound<T>)) -> Result<Self, Self::Error> {
        Ok(OrdRange {
            start: lower.try_into()?,
            end: upper,
        })
    }
}

impl<T> TryFrom<(UpperBound<T>, LowerBound<T>)> for OrdRange<T>
where
    UpperBound<T>: TryInto<LowerBound<T>, Error = RangeBoundError>,
    LowerBound<T>: TryInto<UpperBound<T>, Error = RangeBoundError>,
    T: Clone + Copy,
{
    type Error = RangeBoundError;

    fn try_from((lower, upper): (UpperBound<T>, LowerBound<T>)) -> Result<Self, Self::Error> {
        Ok(OrdRange {
            start: lower.try_into()?,
            end: upper.try_into()?,
        })
    }
}

impl<T> PartialEq for OrdRange<T>
where
    LowerBound<T>: Ord,
    UpperBound<T>: Ord,
{
    fn eq(&self, other: &Self) -> bool {
        self.start == other.start && self.end == other.end
    }
}

impl<T> Eq for OrdRange<T>
where
    LowerBound<T>: Ord,
    UpperBound<T>: Ord,
{
}

impl<T> RangeBounds<T> for OrdRange<T> {
    fn start_bound(&self) -> std::ops::Bound<&T> {
        self.start.0.as_ref()
    }

    fn end_bound(&self) -> std::ops::Bound<&T> {
        self.end.0.as_ref()
    }
}