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 {}