Skip to main content

Interval

Enum Interval 

Source
pub enum Interval<A> {
    Empty,
    Closed {
        lo: A,
        hi: A,
    },
}
Expand description

An interval in a preordered set A.

An interval is a subset I ⊆ A closed under bracketing:

∀ x, y ∈ I, z ∈ A. x ≤ z ≤ y ⇒ z ∈ I.

The Empty variant arises naturally when Interval::new is called with endpoints that are not preorder-comparable (e.g. f64::NAN) or out of order.

§Equality vs containment

Interval carries two distinct relations on the same value:

  • PartialEq / Eq are structural: two Closeds compare equal iff their lo and hi fields are pairwise equal. Empty == Empty. Derived from the field-level PartialEq impl on A.
  • PartialOrd is the containment preorder: Empty ≤ everything; Closed i₁ ≤ Closed i₂ ⟺ i₂ ⊇ i₁. Two Closeds neither of which contains the other (e.g. [1, 4] vs [2, 5]) are incomparable, returning None.

The two are intentionally different: structural equality is the natural equality-up-to-constructor, while containment is the natural lattice-theoretic order. They agree only at Some(Equal), which corresponds to mutual containment (i.e. structural equality of endpoints).

§Why Eq is sound for floating-point A

Eq requires reflexive equality: a == a for all a. For A = f64, NaN breaks this. Soundness here rests on the invariant that no Closed variant ever holds a non-reflexive value, which holds because Interval::new preorder-checks its inputs and routes any partial_cmp returning None to Empty. Direct construction (Interval::Closed { lo: NAN, hi: NAN }) bypasses this gate; callers using the public field syntax must preserve the invariant themselves.

§Examples

use connections::interval::Interval;

let i = Interval::new(1, 3);
assert!(i.contains(&2));
assert!(!i.contains(&5));

// Out-of-order endpoints collapse to Empty.
assert_eq!(Interval::new(3, 1), Interval::Empty);

// NaN is not preorder-comparable to itself, so an interval
// with NaN endpoints is Empty.
let nan = f64::NAN;
assert_eq!(Interval::new(nan, nan), Interval::<f64>::Empty);

Variants§

§

Empty

The empty interval, containing nothing.

§

Closed

A non-empty closed interval [lo, hi] with lo ≤ hi.

Fields

§lo: A

Lower endpoint (inclusive).

§hi: A

Upper endpoint (inclusive).

Implementations§

Source§

impl<A> Interval<A>

Source

pub const fn empty() -> Self

The empty interval. Equivalent to writing Interval::Empty directly — a fn-form constructor for callers that prefer it.

Source

pub fn singleton(a: A) -> Self
where A: Clone,

A singleton interval containing only a.

§Examples
use connections::interval::Interval;
let i = Interval::singleton(7_i32);
assert!(i.contains(&7));
assert!(!i.contains(&8));
Source

pub fn new(x: A, y: A) -> Self
where A: PartialOrd,

Construct an interval from a pair of endpoints. Endpoints are preorder-checked, not sorted: if x ≤ y then Closed { lo: x, hi: y }; otherwise (x > y or x and y incomparable — e.g. an antichain pair in a partial order) the result is Interval::Empty. Reversed endpoints are not swapped.

§Examples
use connections::interval::Interval;
// In-order endpoints retained:
assert!(matches!(
    Interval::new(1, 3),
    Interval::Closed { lo: 1, hi: 3 }
));
// Reversed endpoints collapse:
assert_eq!(Interval::new(3, 1), Interval::<i32>::Empty);
// Equal endpoints produce a singleton.
assert!(matches!(
    Interval::new(2, 2),
    Interval::Closed { lo: 2, hi: 2 }
));
Source

pub fn endpts(self) -> Option<(A, A)>

Extract the endpoints of a bounded interval; returns None for Interval::Empty.

Source

pub fn contains(&self, p: &A) -> bool
where A: PartialOrd,

True iff p lies in the closed interval [lo, hi]. Empty contains nothing.

§Examples
use connections::interval::Interval;
assert!(Interval::new(1, 3).contains(&2));
assert!(!Interval::<i32>::Empty.contains(&0));
Source

pub fn imap<B, F>(self, f: F) -> Interval<B>
where F: Fn(A) -> B, B: PartialOrd,

Map over an interval, re-sorting the result. A non-monotonic f may collapse the result to Interval::Empty because the new endpoints are re-checked via Interval::new — this is intentional, and the same behaviour as the Haskell original.

§Examples
use connections::interval::Interval;
// Monotone +1: endpoints map and remain in order.
assert!(matches!(
    Interval::new(1_i32, 3).imap(|x| x + 1),
    Interval::Closed { lo: 2, hi: 4 }
));
// Antimonotone negate over a non-singleton: lo and hi
// swap, so `Interval::new` sees a reversed pair and
// collapses to Empty.
assert_eq!(
    Interval::new(1_i32, 3).imap(|x| -x),
    Interval::<i32>::Empty
);
// Singletons survive any function.
assert!(matches!(
    Interval::singleton(2_i32).imap(|x| -x),
    Interval::Closed { lo: -2, hi: -2 }
));

Trait Implementations§

Source§

impl<A: Clone> Clone for Interval<A>

Source§

fn clone(&self) -> Interval<A>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<A: Copy> Copy for Interval<A>

Source§

impl<A: Debug> Debug for Interval<A>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<A> Default for Interval<A>

Source§

fn default() -> Interval<A>

Returns the “default value” for a type. Read more
Source§

impl<A: Eq> Eq for Interval<A>

Source§

impl<A: Hash> Hash for Interval<A>

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<A: PartialEq> PartialEq for Interval<A>

Source§

fn eq(&self, other: &Interval<A>) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl<A: PartialOrd> PartialOrd for Interval<A>

Containment preorder: Empty ≤ everything; Closed i₁ ≤ Closed i₂ ⟺ i₂ ⊇ i₁ (i.e. lo₂ ≤ lo₁ && hi₁ ≤ hi₂).

Two Closed intervals neither of which contains the other (e.g. [1,4] vs [2,5]) are incomparable, returning None.

§Consistency with PartialEq / Eq

std::cmp::PartialOrd requires partial_cmp(a, b) == Some(Equal) ⟺ a == b. The two relations on Interval<A> are intentionally different (containment vs structural), but they agree at equality:

  • Empty.partial_cmp(&Empty) == Some(Equal) and Empty == Empty. ✓
  • Closed { lo: l₁, hi: h₁ }.partial_cmp(&Closed { lo: l₂, hi: h₂ }) == Some(Equal) iff (i₁ ⊆ i₂) ∧ (i₂ ⊆ i₁), which expands to (l₂ ≤ l₁ ∧ h₁ ≤ h₂) ∧ (l₁ ≤ l₂ ∧ h₂ ≤ h₁). By PartialOrd’s antisymmetry on A this gives l₁ = l₂ ∧ h₁ = h₂, i.e. structural equality, i.e. Closed{l₁,h₁} == Closed{l₂,h₂}. ✓

So the contract holds: structural eq and mutual containment coincide on every variant pair.

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 (const: unstable) · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 (const: unstable) · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 (const: unstable) · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 (const: unstable) · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<A: PartialEq> StructuralPartialEq for Interval<A>

Auto Trait Implementations§

§

impl<A> Freeze for Interval<A>
where A: Freeze,

§

impl<A> RefUnwindSafe for Interval<A>
where A: RefUnwindSafe,

§

impl<A> Send for Interval<A>
where A: Send,

§

impl<A> Sync for Interval<A>
where A: Sync,

§

impl<A> Unpin for Interval<A>
where A: Unpin,

§

impl<A> UnsafeUnpin for Interval<A>
where A: UnsafeUnpin,

§

impl<A> UnwindSafe for Interval<A>
where A: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Az for T

Source§

fn az<Dst>(self) -> Dst
where T: Cast<Dst>,

Casts the value.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<Src, Dst> CastFrom<Src> for Dst
where Src: Cast<Dst>,

Source§

fn cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CheckedAs for T

Source§

fn checked_as<Dst>(self) -> Option<Dst>
where T: CheckedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> CheckedCastFrom<Src> for Dst
where Src: CheckedCast<Dst>,

Source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<Src, Dst> LosslessTryInto<Dst> for Src
where Dst: LosslessTryFrom<Src>,

Source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
Source§

impl<Src, Dst> LossyInto<Dst> for Src
where Dst: LossyFrom<Src>,

Source§

fn lossy_into(self) -> Dst

Performs the conversion.
Source§

impl<T> OverflowingAs for T

Source§

fn overflowing_as<Dst>(self) -> (Dst, bool)
where T: OverflowingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dst
where Src: OverflowingCast<Dst>,

Source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> SaturatingAs for T

Source§

fn saturating_as<Dst>(self) -> Dst
where T: SaturatingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dst
where Src: SaturatingCast<Dst>,

Source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> StrictAs for T

Source§

fn strict_as<Dst>(self) -> Dst
where T: StrictCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> StrictCastFrom<Src> for Dst
where Src: StrictCast<Dst>,

Source§

fn strict_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> UnwrappedAs for T

Source§

fn unwrapped_as<Dst>(self) -> Dst
where T: UnwrappedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dst
where Src: UnwrappedCast<Dst>,

Source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WrappingAs for T

Source§

fn wrapping_as<Dst>(self) -> Dst
where T: WrappingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> WrappingCastFrom<Src> for Dst
where Src: WrappingCast<Dst>,

Source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.