Skip to main content

int_interval/
traits.rs

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