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