Skip to main content

int_interval/
traits.rs

1use crate::{OneTwo, ZeroOneTwo};
2
3pub(crate) mod forwarding;
4pub(crate) use forwarding::impl_co_forwarding;
5
6mod sealed;
7
8/// Built-in integer coordinate type accepted by closed-open intervals.
9pub trait IntPrimitive: sealed::Int {
10    fn as_f32(self) -> f32;
11    fn as_f64(self) -> f64;
12}
13
14impl<T> IntPrimitive for T
15where
16    T: sealed::Int,
17{
18    #[inline]
19    fn as_f32(self) -> f32 {
20        sealed::Int::as_f32(self)
21    }
22
23    #[inline]
24    fn as_f64(self) -> f64 {
25        sealed::Int::as_f64(self)
26    }
27}
28
29/// Built-in unsigned integer type used for exact interval measures.
30pub trait UnsignedPrimitive: IntPrimitive + sealed::Unsigned {}
31
32impl<T> UnsignedPrimitive for T where T: IntPrimitive + sealed::Unsigned {}
33
34/// Primitive types associated with a closed-open integer interval.
35pub trait COPrimitive {
36    type CoordType: IntPrimitive;
37    type MeasureType: UnsignedPrimitive;
38}
39
40/// Construction capability for a valid closed-open interval.
41///
42/// Implementations must preserve the invariant:
43///
44/// ```text
45/// start < end_excl
46/// ```
47pub trait COConstruct: COPrimitive + Sized {
48    /// Constructs `[start, end_excl)`, returning `None` for an empty or
49    /// reversed interval.
50    fn try_new(start: Self::CoordType, end_excl: Self::CoordType) -> Option<Self>;
51
52    /// Constructs `[start, end_excl)` without checking the interval invariant.
53    ///
54    /// # Safety
55    ///
56    /// The caller must guarantee that:
57    ///
58    /// ```text
59    /// start < end_excl
60    /// ```
61    unsafe fn new_unchecked(start: Self::CoordType, end_excl: Self::CoordType) -> Self;
62}
63
64/// Construction capability based on a midpoint and an exact interval measure.
65///
66/// `len` is represented by the interval's exact unsigned measure type.
67pub trait COMidpointConstruct: COConstruct {
68    /// Constructs an interval centered around `mid` with exact length `len`.
69    ///
70    /// Returns `None` when `len` is zero or when the resulting bounds cannot
71    /// be represented by `CoordType`.
72    fn checked_from_midpoint_len(mid: Self::CoordType, len: Self::MeasureType) -> Option<Self>;
73
74    /// Constructs an interval centered around `mid` with saturating endpoint
75    /// arithmetic.
76    ///
77    /// Returns `None` when `len` is zero or saturation collapses the result
78    /// into an empty interval.
79    fn saturating_from_midpoint_len(mid: Self::CoordType, len: Self::MeasureType) -> Option<Self>;
80}
81
82/// Construction capability based on a start bound and an exact interval measure.
83///
84/// `len` is represented by the interval's exact unsigned measure type.
85pub trait COStartLenConstruct: COConstruct {
86    /// Constructs an interval starting at `start` with exact length `len`.
87    ///
88    /// The resulting interval is:
89    ///
90    /// ```text
91    /// [start, start + len)
92    /// ```
93    ///
94    /// Returns `None` when `len` is zero or when the resulting exclusive end
95    /// bound cannot be represented by `CoordType`.
96    fn checked_from_start_len(start: Self::CoordType, len: Self::MeasureType) -> Option<Self>;
97
98    /// Constructs an interval starting at `start` with saturating endpoint
99    /// arithmetic.
100    ///
101    /// The resulting interval starts at `start`, while the exclusive end bound
102    /// is clamped to the maximum representable coordinate when needed.
103    ///
104    /// Returns `None` when `len` is zero or saturation collapses the result
105    /// into an empty interval.
106    fn saturating_from_start_len(start: Self::CoordType, len: Self::MeasureType) -> Option<Self>;
107}
108
109/// Boundary access capability for a closed-open interval.
110pub trait COBounds: COPrimitive + Copy + Ord + Eq + core::fmt::Debug {
111    /// Returns the inclusive lower bound.
112    fn start(self) -> Self::CoordType;
113
114    /// Returns the exclusive upper bound.
115    fn end_excl(self) -> Self::CoordType;
116
117    /// Returns the inclusive upper bound.
118    ///
119    /// This is the greatest coordinate contained in the interval.
120    fn end_incl(self) -> Self::CoordType;
121}
122
123/// Containment and overlap predicates for closed-open intervals.
124pub trait COPredicates: COBounds {
125    /// Returns whether `x` is contained in this interval.
126    fn contains(self, x: Self::CoordType) -> bool;
127
128    /// Returns whether `other` is fully contained in this interval.
129    fn contains_interval(self, other: Self) -> bool;
130
131    /// Returns whether this interval and `other` overlap with positive length.
132    fn intersects(self, other: Self) -> bool;
133
134    /// Returns whether this interval and `other` touch at exactly one boundary
135    /// without overlapping.
136    fn is_adjacent(self, other: Self) -> bool;
137
138    /// Returns whether this interval and `other` overlap or are adjacent.
139    fn is_contiguous_with(self, other: Self) -> bool;
140}
141
142/// Range projection capability for a closed-open interval.
143///
144/// The returned range has the same half-open semantics as the interval:
145///
146/// ```text
147/// [start, end_excl) -> start..end_excl
148/// ```
149pub trait CORange: COBounds + Sized {
150    /// Returns the standard-library half-open range represented by this
151    /// interval.
152    fn to_range(self) -> core::ops::Range<Self::CoordType>;
153
154    /// Returns the standard-library range used to iterate covered coordinates.
155    ///
156    /// This is equivalent to `self.to_range()`.
157    #[inline]
158    fn iter(self) -> core::ops::Range<Self::CoordType> {
159        self.to_range()
160    }
161}
162
163/// Algebraic operations for closed-open intervals.
164pub trait COAlgebra: COConstruct + COBounds + COPredicates {
165    /// Returns the overlapping region of two intervals, if any.
166    fn intersection(self, other: Self) -> Option<Self>;
167
168    /// Returns the smallest interval containing both intervals.
169    fn convex_hull(self, other: Self) -> Self;
170
171    /// Returns the interval strictly between two separated intervals.
172    ///
173    /// Returns `None` when the intervals overlap or are adjacent.
174    fn between(self, other: Self) -> Option<Self>;
175
176    /// Returns the union of two intervals.
177    ///
178    /// Contiguous intervals are merged into one interval; otherwise the two
179    /// intervals are returned in ascending order.
180    fn union(self, other: Self) -> OneTwo<Self>;
181
182    /// Returns `self \ other`.
183    ///
184    /// The result may contain zero, one, or two residual intervals.
185    fn difference(self, other: Self) -> ZeroOneTwo<Self>;
186
187    /// Returns the symmetric difference of two intervals.
188    ///
189    /// The result contains points covered by exactly one operand and may
190    /// contain zero, one, or two intervals.
191    fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self>;
192}
193
194/// Exact measure capability for a closed-open interval.
195pub trait COMeasure: COPrimitive {
196    /// Returns the exact interval length.
197    fn len(self) -> Self::MeasureType;
198}
199
200/// Representative-position capability for a closed-open interval.
201pub trait COMidpoint: COPrimitive {
202    /// Returns the midpoint coordinate, using floor rounding where required.
203    fn midpoint(self) -> Self::CoordType;
204}
205
206/// Exact checked Minkowski operations whose images remain closed-open
207/// integer intervals.
208pub trait COCheckedMinkowskiLinear: COPrimitive + Sized {
209    /// Returns the exact Minkowski sum `self + other`.
210    fn checked_minkowski_add(self, other: Self) -> Option<Self>;
211
212    /// Returns the exact Minkowski subtraction `self - other`.
213    fn checked_minkowski_sub(self, other: Self) -> Option<Self>;
214
215    /// Returns the exact translation `self + scalar`.
216    fn checked_minkowski_add_scalar(self, scalar: Self::CoordType) -> Option<Self>;
217
218    /// Returns the exact translation `self - scalar`.
219    fn checked_minkowski_sub_scalar(self, scalar: Self::CoordType) -> Option<Self>;
220}
221
222/// Checked interval hulls of non-linear Minkowski images.
223///
224/// For discrete integer intervals, multiplication and division may produce
225/// non-contiguous point sets. These methods return a containing interval hull,
226/// not necessarily an exact image.
227pub trait COCheckedMinkowskiHull: COPrimitive + Sized {
228    /// Returns the interval hull containing every point in `self * other`.
229    fn checked_minkowski_mul_hull(self, other: Self) -> Option<Self>;
230
231    /// Returns the interval hull containing every point in `self / other`.
232    fn checked_minkowski_div_hull(self, other: Self) -> Option<Self>;
233
234    /// Returns the interval hull containing every point in `self * scalar`.
235    fn checked_minkowski_mul_scalar_hull(self, scalar: Self::CoordType) -> Option<Self>;
236
237    /// Returns the interval hull containing every point in `self / scalar`.
238    fn checked_minkowski_div_scalar_hull(self, scalar: Self::CoordType) -> Option<Self>;
239}
240
241/// Saturating Minkowski operations whose results remain closed-open integer
242/// intervals after endpoint arithmetic is clamped to the representable domain.
243///
244/// These methods apply saturating arithmetic to the interval bounds rather
245/// than returning an error on overflow or underflow.
246///
247/// When saturation clips a bound, the returned interval is the representable
248/// saturated result, not necessarily the exact unconstrained mathematical
249/// image.
250///
251/// Returns `None` when saturation collapses the resulting interval into an
252/// empty or otherwise invalid closed-open interval.
253pub trait COSaturatingMinkowskiLinear: COPrimitive + Sized {
254    /// Returns the saturated Minkowski sum `self + other`.
255    ///
256    /// Both result bounds are computed with saturating addition.
257    fn saturating_minkowski_add(self, other: Self) -> Option<Self>;
258
259    /// Returns the saturated Minkowski subtraction `self - other`.
260    ///
261    /// Both result bounds are computed with saturating subtraction.
262    fn saturating_minkowski_sub(self, other: Self) -> Option<Self>;
263
264    /// Returns the saturated translation `self + scalar`.
265    ///
266    /// Both interval bounds are shifted with saturating addition.
267    fn saturating_minkowski_add_scalar(self, scalar: Self::CoordType) -> Option<Self>;
268
269    /// Returns the saturated translation `self - scalar`.
270    ///
271    /// Both interval bounds are shifted with saturating subtraction.
272    fn saturating_minkowski_sub_scalar(self, scalar: Self::CoordType) -> Option<Self>;
273}
274
275/// Saturating interval hulls of non-linear Minkowski images.
276///
277/// For discrete integer intervals, multiplication and division may produce
278/// non-contiguous point sets. These methods first compute a containing
279/// interval hull and apply saturating endpoint arithmetic where needed.
280///
281/// When saturation clips a bound, the returned interval is a representable
282/// saturated hull rather than the exact unconstrained mathematical image.
283///
284/// Returns `None` when the operation is undefined, such as division by zero,
285/// or when saturation collapses the resulting hull into an empty or otherwise
286/// invalid closed-open interval.
287pub trait COSaturatingMinkowskiHull: COPrimitive + Sized {
288    /// Returns the saturated interval hull of `self * other`.
289    ///
290    /// Endpoint products are computed with saturating multiplication.
291    fn saturating_minkowski_mul_hull(self, other: Self) -> Option<Self>;
292
293    /// Returns the saturated interval hull of `self / other`.
294    ///
295    /// Returns `None` when the divisor interval contains zero in a position
296    /// that makes the interval division undefined.
297    fn saturating_minkowski_div_hull(self, other: Self) -> Option<Self>;
298
299    /// Returns the saturated interval hull of `self * scalar`.
300    ///
301    /// Endpoint products are computed with saturating multiplication.
302    fn saturating_minkowski_mul_scalar_hull(self, scalar: Self::CoordType) -> Option<Self>;
303
304    /// Returns the saturated interval hull of `self / scalar`.
305    ///
306    /// Returns `None` when `scalar` is zero.
307    fn saturating_minkowski_div_scalar_hull(self, scalar: Self::CoordType) -> Option<Self>;
308}
309
310/// Complete closed-open integer interval capability required by interval sets.
311pub trait IntCO: COConstruct + COBounds + COPredicates + COAlgebra + COMeasure {}
312
313impl<T> IntCO for T where T: COConstruct + COBounds + COPredicates + COAlgebra + COMeasure {}