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/// Boundary access capability for a closed-open interval.
83pub trait COBounds: COPrimitive + Copy + Ord + Eq + core::fmt::Debug {
84 /// Returns the inclusive lower bound.
85 fn start(self) -> Self::CoordType;
86
87 /// Returns the exclusive upper bound.
88 fn end_excl(self) -> Self::CoordType;
89
90 /// Returns the inclusive upper bound.
91 ///
92 /// This is the greatest coordinate contained in the interval.
93 fn end_incl(self) -> Self::CoordType;
94}
95
96/// Containment and overlap predicates for closed-open intervals.
97pub trait COPredicates: COBounds {
98 /// Returns whether `x` is contained in this interval.
99 fn contains(self, x: Self::CoordType) -> bool;
100
101 /// Returns whether `other` is fully contained in this interval.
102 fn contains_interval(self, other: Self) -> bool;
103
104 /// Returns whether this interval and `other` overlap with positive length.
105 fn intersects(self, other: Self) -> bool;
106
107 /// Returns whether this interval and `other` touch at exactly one boundary
108 /// without overlapping.
109 fn is_adjacent(self, other: Self) -> bool;
110
111 /// Returns whether this interval and `other` overlap or are adjacent.
112 fn is_contiguous_with(self, other: Self) -> bool;
113}
114
115/// Range projection capability for a closed-open interval.
116///
117/// The returned range has the same half-open semantics as the interval:
118///
119/// ```text
120/// [start, end_excl) -> start..end_excl
121/// ```
122pub trait CORange: COBounds + Sized {
123 /// Returns the standard-library half-open range represented by this
124 /// interval.
125 fn to_range(self) -> core::ops::Range<Self::CoordType>;
126
127 /// Returns the standard-library range used to iterate covered coordinates.
128 ///
129 /// This is equivalent to `self.to_range()`.
130 #[inline]
131 fn iter(self) -> core::ops::Range<Self::CoordType> {
132 self.to_range()
133 }
134}
135
136/// Algebraic operations for closed-open intervals.
137pub trait COAlgebra: COConstruct + COBounds + COPredicates {
138 /// Returns the overlapping region of two intervals, if any.
139 fn intersection(self, other: Self) -> Option<Self>;
140
141 /// Returns the smallest interval containing both intervals.
142 fn convex_hull(self, other: Self) -> Self;
143
144 /// Returns the interval strictly between two separated intervals.
145 ///
146 /// Returns `None` when the intervals overlap or are adjacent.
147 fn between(self, other: Self) -> Option<Self>;
148
149 /// Returns the union of two intervals.
150 ///
151 /// Contiguous intervals are merged into one interval; otherwise the two
152 /// intervals are returned in ascending order.
153 fn union(self, other: Self) -> OneTwo<Self>;
154
155 /// Returns `self \ other`.
156 ///
157 /// The result may contain zero, one, or two residual intervals.
158 fn difference(self, other: Self) -> ZeroOneTwo<Self>;
159
160 /// Returns the symmetric difference of two intervals.
161 ///
162 /// The result contains points covered by exactly one operand and may
163 /// contain zero, one, or two intervals.
164 fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self>;
165}
166
167/// Exact measure capability for a closed-open interval.
168pub trait COMeasure: COPrimitive {
169 /// Returns the exact interval length.
170 fn len(self) -> Self::MeasureType;
171}
172
173/// Representative-position capability for a closed-open interval.
174pub trait COMidpoint: COPrimitive {
175 /// Returns the midpoint coordinate, using floor rounding where required.
176 fn midpoint(self) -> Self::CoordType;
177}
178
179/// Exact checked Minkowski operations whose images remain closed-open
180/// integer intervals.
181pub trait COCheckedMinkowskiLinear: COPrimitive + Sized {
182 /// Returns the exact Minkowski sum `self + other`.
183 fn checked_minkowski_add(self, other: Self) -> Option<Self>;
184
185 /// Returns the exact Minkowski subtraction `self - other`.
186 fn checked_minkowski_sub(self, other: Self) -> Option<Self>;
187
188 /// Returns the exact translation `self + scalar`.
189 fn checked_minkowski_add_scalar(self, scalar: Self::CoordType) -> Option<Self>;
190
191 /// Returns the exact translation `self - scalar`.
192 fn checked_minkowski_sub_scalar(self, scalar: Self::CoordType) -> Option<Self>;
193}
194
195/// Checked interval hulls of non-linear Minkowski images.
196///
197/// For discrete integer intervals, multiplication and division may produce
198/// non-contiguous point sets. These methods return a containing interval hull,
199/// not necessarily an exact image.
200pub trait COCheckedMinkowskiHull: COPrimitive + Sized {
201 /// Returns the interval hull containing every point in `self * other`.
202 fn checked_minkowski_mul_hull(self, other: Self) -> Option<Self>;
203
204 /// Returns the interval hull containing every point in `self / other`.
205 fn checked_minkowski_div_hull(self, other: Self) -> Option<Self>;
206
207 /// Returns the interval hull containing every point in `self * scalar`.
208 fn checked_minkowski_mul_scalar_hull(self, scalar: Self::CoordType) -> Option<Self>;
209
210 /// Returns the interval hull containing every point in `self / scalar`.
211 fn checked_minkowski_div_scalar_hull(self, scalar: Self::CoordType) -> Option<Self>;
212}
213
214/// Saturating Minkowski operations whose results remain closed-open integer
215/// intervals after endpoint arithmetic is clamped to the representable domain.
216///
217/// These methods apply saturating arithmetic to the interval bounds rather
218/// than returning an error on overflow or underflow.
219///
220/// When saturation clips a bound, the returned interval is the representable
221/// saturated result, not necessarily the exact unconstrained mathematical
222/// image.
223///
224/// Returns `None` when saturation collapses the resulting interval into an
225/// empty or otherwise invalid closed-open interval.
226pub trait COSaturatingMinkowskiLinear: COPrimitive + Sized {
227 /// Returns the saturated Minkowski sum `self + other`.
228 ///
229 /// Both result bounds are computed with saturating addition.
230 fn saturating_minkowski_add(self, other: Self) -> Option<Self>;
231
232 /// Returns the saturated Minkowski subtraction `self - other`.
233 ///
234 /// Both result bounds are computed with saturating subtraction.
235 fn saturating_minkowski_sub(self, other: Self) -> Option<Self>;
236
237 /// Returns the saturated translation `self + scalar`.
238 ///
239 /// Both interval bounds are shifted with saturating addition.
240 fn saturating_minkowski_add_scalar(self, scalar: Self::CoordType) -> Option<Self>;
241
242 /// Returns the saturated translation `self - scalar`.
243 ///
244 /// Both interval bounds are shifted with saturating subtraction.
245 fn saturating_minkowski_sub_scalar(self, scalar: Self::CoordType) -> Option<Self>;
246}
247
248/// Saturating interval hulls of non-linear Minkowski images.
249///
250/// For discrete integer intervals, multiplication and division may produce
251/// non-contiguous point sets. These methods first compute a containing
252/// interval hull and apply saturating endpoint arithmetic where needed.
253///
254/// When saturation clips a bound, the returned interval is a representable
255/// saturated hull rather than the exact unconstrained mathematical image.
256///
257/// Returns `None` when the operation is undefined, such as division by zero,
258/// or when saturation collapses the resulting hull into an empty or otherwise
259/// invalid closed-open interval.
260pub trait COSaturatingMinkowskiHull: COPrimitive + Sized {
261 /// Returns the saturated interval hull of `self * other`.
262 ///
263 /// Endpoint products are computed with saturating multiplication.
264 fn saturating_minkowski_mul_hull(self, other: Self) -> Option<Self>;
265
266 /// Returns the saturated interval hull of `self / other`.
267 ///
268 /// Returns `None` when the divisor interval contains zero in a position
269 /// that makes the interval division undefined.
270 fn saturating_minkowski_div_hull(self, other: Self) -> Option<Self>;
271
272 /// Returns the saturated interval hull of `self * scalar`.
273 ///
274 /// Endpoint products are computed with saturating multiplication.
275 fn saturating_minkowski_mul_scalar_hull(self, scalar: Self::CoordType) -> Option<Self>;
276
277 /// Returns the saturated interval hull of `self / scalar`.
278 ///
279 /// Returns `None` when `scalar` is zero.
280 fn saturating_minkowski_div_scalar_hull(self, scalar: Self::CoordType) -> Option<Self>;
281}
282
283/// Complete closed-open integer interval capability required by interval sets.
284pub trait IntCO: COConstruct + COBounds + COPredicates + COAlgebra + COMeasure {}
285
286impl<T> IntCO for T where T: COConstruct + COBounds + COPredicates + COAlgebra + COMeasure {}