1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! Mathematical intervals, i.g., [a, b], (a, b), [a, b), and (a, b].
//! Also supports multi-dimensional axis-aligned boxes.
//!
//! # Interval
//! Intervals like *[a, b]*, *(a, b)*, *[a, b)*, and *(a, b]* for any `PartialOrd` type.
//!
//! ```
//! use inter_val::{Inclusive, Exclusive, Interval};
//!
//! // Closed interval of i32
//! let a = Inclusive.at(0).to(Inclusive.at(10));  // [0, 10]
//! assert!(a.contains(&3));
//!
//! // Half-open interval of f64
//! let b = Inclusive.at(1.23).to(Exclusive.at(4.56));   // [1.23, 4.56)
//! assert!(!b.contains(&4.56));
//! assert!(b.contains(&(4.56 - 0.000000000000001)));
//!
//! // Intersection
//! let c = Inclusive.between(5, 15);  // [5, 15]
//! let isect = a.intersection(&c).unwrap(); // [0, 10] ∩ [5, 15] = [5, 10]
//! assert_eq!(isect.inf(), &5);
//! assert_eq!(isect.sup(), &10);
//!
//! // Span & Gap
//! let d = Inclusive.between(12, 15);  // [12, 15]
//! let span = a.span(&d);  // [0, 15]
//! let gap = a.gap(&d);    // (10, 12)
//! assert_eq!(span, Inclusive.between(0, 15));
//! assert_eq!(gap.unwrap(), Exclusive.between(10, 12));
//!
//! // Union
//! let union = a.union(&d);
//! assert_eq!(union.span, span);
//! assert_eq!(union.gap, gap);
//! assert_eq!(union.into_vec(), vec![a, d]);
//!
//! // Hull
//! let a = Interval::<_>::hull_many(vec![3, 9, 2, 5]).unwrap(); // [2, 9]
//! assert_eq!(a, Inclusive.between(2, 9));
//! ```
//!
//! # Multi-dimensional axis-aligned box
//! Boxes represented by Cartesian product of intervals.
//! ```
//! use inter_val::{Box2, Inclusive};
//!
//! // [0.0, 10.0] × [5.0, 20.0]
//! let a: Box2<f64> = Box2::new(Inclusive.between(0.0, 10.0), Inclusive.between(5.0, 20.0));
//!
//! // Another way to construct [0.0, 10.0] × [5.0, 20.0]
//! let b: Box2<f64> = Box2::between(&[0.0, 5.0], &[10.0, 20.0]);
//! assert_eq!(a, b);
//!
//! // Hull
//! let b = a.hull(&[12.3, 7.5]);
//! assert_eq!(b, Box2::between(&[0.0, 5.0], &[12.3, 20.0]));
//! ```
mod bound;
mod bound_type;
mod converters;
mod half;
mod interval;
mod interval_box;
mod ndim;
mod nullable;
mod std_range;
mod tests;
mod traits;

use bound_type::{Left, Right};
use traits::BoundaryOf;

pub use bound::Bound;
pub use bound_type::{BoundType, Exclusive, Inclusive};
pub use half::{HalfBounded, LeftBounded, RightBounded};
pub use interval::Interval;
pub use interval_box::BoxN;
pub use ndim::NDim;
pub use nullable::Nullable;

impl Inclusive {
    pub fn at<T>(self, t: T) -> Bound<T, Self> {
        Bound {
            limit: t,
            bound_type: self,
        }
    }
    pub fn between<T: PartialOrd>(self, a: T, b: T) -> Interval<T, Self, Self> {
        Interval::between(a, b)
    }
    pub fn hull<T: PartialOrd + Clone>(
        items: impl IntoIterator<Item = T>,
    ) -> Option<Interval<T, Self, Self>> {
        Interval::hull_many(items)
    }
}
impl Exclusive {
    pub fn at<T>(self, t: T) -> Bound<T, Self> {
        Bound {
            limit: t,
            bound_type: self,
        }
    }
    pub fn try_between<T: PartialOrd>(self, a: T, b: T) -> Option<Interval<T, Self, Self>> {
        Interval::try_between(a, b)
    }
    pub fn between<T: PartialOrd>(self, a: T, b: T) -> Interval<T, Self, Self> {
        Interval::between(a, b)
    }
    pub fn hull<T: PartialOrd + Clone>(
        items: impl IntoIterator<Item = T>,
    ) -> Option<Interval<T, Self, Self>> {
        Interval::hull_many(items)
    }
}
impl BoundType {
    pub fn at<T>(self, t: T) -> Bound<T, Self> {
        Bound {
            limit: t,
            bound_type: self,
        }
    }
    pub fn try_between<T: PartialOrd>(self, a: T, b: T) -> Option<Interval<T, Self, Self>> {
        if a <= b {
            Interval::try_new(self.at(a), self.at(b))
        } else {
            Interval::try_new(self.at(b), self.at(a))
        }
    }
}

impl<T: PartialOrd, B: BoundaryOf<Left>> Bound<T, B> {
    pub fn to<R: BoundaryOf<Right>>(self, r: Bound<T, R>) -> Interval<T, B, R> {
        Interval::new(self, r)
    }
    pub fn try_to<R: BoundaryOf<Right>>(self, r: Bound<T, R>) -> Option<Interval<T, B, R>> {
        Interval::try_new(self, r)
    }
}

#[derive(Debug, thiserror::Error)]
#[error("left boundary must be less than or equal to right boundary")]
pub struct IntervalIsEmpty;

pub type OpenInterval<T> = Interval<T, Exclusive>;
pub type GeneralInterval<T> = Interval<T, BoundType>;
pub type Box2<T, L = Inclusive, R = L> = BoxN<2, T, L, R>;
pub type Box3<T, L = Inclusive, R = L> = BoxN<3, T, L, R>;
pub type Box4<T, L = Inclusive, R = L> = BoxN<4, T, L, R>;