int_intervals/interval/u32.rs
1// -----------------------------------------------------------------------------
2// @generated by xtask/codegen (unsigned)
3// DO NOT EDIT MANUALLY.
4// Changes will be overwritten.
5// -----------------------------------------------------------------------------
6
7use crate::interval::res::{OneTwo, ZeroOneTwo};
8
9#[cfg(test)]
10mod tests_for_between;
11#[cfg(test)]
12mod tests_for_checked_minkowski;
13#[cfg(test)]
14mod tests_for_convex_hull;
15#[cfg(test)]
16mod tests_for_difference;
17#[cfg(test)]
18mod tests_for_intersection;
19#[cfg(test)]
20mod tests_for_midpoint;
21#[cfg(test)]
22mod tests_for_saturating_minkowski;
23#[cfg(test)]
24mod tests_for_start_len;
25#[cfg(test)]
26mod tests_for_symmetric_difference;
27#[cfg(test)]
28mod tests_for_try_from_range;
29#[cfg(test)]
30mod tests_for_union;
31
32#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
33pub struct U32CO {
34 start: u32,
35 end_excl: u32,
36}
37
38// ------------------------------------------------------------
39// low-level api: construction / accessors / predicates
40// ------------------------------------------------------------
41
42mod basic {
43
44 use super::*;
45
46 impl U32CO {
47 #[inline]
48 pub const fn try_new(start: u32, end_excl: u32) -> Option<Self> {
49 if start < end_excl {
50 Some(Self { start, end_excl })
51 } else {
52 None
53 }
54 }
55
56 #[inline]
57 pub const unsafe fn new_unchecked(start: u32, end_excl: u32) -> Self {
58 debug_assert!(start < end_excl);
59 Self { start, end_excl }
60 }
61
62 /// Construct a `U32CO` from a start position and a length.
63 ///
64 /// The resulting interval is `[start, start + len)`.
65 ///
66 /// Returns `None` if:
67 /// - `len == 0`;
68 /// - `start + len` overflows `u32`.
69 #[inline]
70 pub const fn checked_from_start_len(start: u32, len: u32) -> Option<Self> {
71 if len == 0 {
72 return None;
73 }
74
75 let Some(end_excl) = start.checked_add(len) else {
76 return None;
77 };
78
79 // SAFETY:
80 // `checked_add` guarantees no overflow, and `len > 0`
81 // guarantees `start < end_excl`.
82 Some(unsafe { Self::new_unchecked(start, end_excl) })
83 }
84
85 /// Construct a `U32CO` from a start position and a length,
86 /// saturating the exclusive end bound on overflow.
87 ///
88 /// The resulting interval is `[start, start.saturating_add(len))`.
89 ///
90 /// Returns `None` if:
91 /// - `len == 0`;
92 /// - saturation still produces an empty interval, e.g. `start == u32::MAX`.
93 #[inline]
94 pub const fn saturating_from_start_len(start: u32, len: u32) -> Option<Self> {
95 if len == 0 {
96 return None;
97 }
98
99 let end_excl = start.saturating_add(len);
100
101 Self::try_new(start, end_excl)
102 }
103
104 /// Construct a `U32CO` from a midpoint and a length.
105 ///
106 /// Returns `None` if the computed interval is invalid or overflows u32.
107 #[inline]
108 pub const fn checked_from_midpoint_len(mid: u32, len: u32) -> Option<Self> {
109 if len == 0 {
110 return None;
111 }
112 // Compute start = mid - floor(len/2)
113 let Some(start) = mid.checked_sub(len / 2) else {
114 return None;
115 };
116 // Compute end_excl = start + len, return None if overflow
117 let Some(end_excl) = start.checked_add(len) else {
118 return None;
119 };
120
121 // # Safety
122 // This function uses `unsafe { Self::new_unchecked(start, end_excl) }` internally.
123 // The safety is guaranteed by the following checks:
124 // 1. `mid.checked_sub(len / 2)` ensures `start` does not underflow `u32`.
125 // 2. `start.checked_add(len)` ensures `end_excl` does not overflow `u32`.
126 // 3. Because `len > 0`, we have `start < end_excl`.
127 // 4. Therefore, the half-open interval invariant `[start, end_excl)` is preserved.
128 Some(unsafe { Self::new_unchecked(start, end_excl) })
129 }
130
131 /// Saturating version: from midpoint + length, keeps start < end_excl
132 #[inline]
133 pub const fn saturating_from_midpoint_len(mid: u32, len: u32) -> Option<Self> {
134 if len == 0 {
135 return None;
136 }
137
138 let start = mid.saturating_sub(len / 2);
139 let end_excl = start.saturating_add(len);
140
141 // Use try_new to enforce start < end_excl invariant
142 Self::try_new(start, end_excl)
143 }
144 }
145
146 impl U32CO {
147 #[inline]
148 pub const fn start(self) -> u32 {
149 self.start
150 }
151
152 #[inline]
153 pub const fn end_excl(self) -> u32 {
154 self.end_excl
155 }
156
157 #[inline]
158 pub const fn end_incl(self) -> u32 {
159 // u32_low_bound =< start < end_excl
160 self.end_excl - 1
161 }
162 }
163
164 impl U32CO {
165 #[inline]
166 pub const fn len(self) -> u32 {
167 self.end_excl - self.start
168 }
169 }
170
171 impl U32CO {
172 /// Returns the midpoint of the interval (floor division).
173 #[inline]
174 pub const fn midpoint(self) -> u32 {
175 self.start + (self.len() / 2)
176 }
177 }
178
179 impl U32CO {
180 #[inline]
181 pub const fn contains(self, x: u32) -> bool {
182 self.start <= x && x < self.end_excl
183 }
184
185 #[inline]
186 pub const fn contains_interval(self, other: Self) -> bool {
187 self.start <= other.start && other.end_excl <= self.end_excl
188 }
189
190 #[inline]
191 pub const fn intersects(self, other: Self) -> bool {
192 !(self.end_excl <= other.start || other.end_excl <= self.start)
193 }
194
195 #[inline]
196 pub const fn is_adjacent(self, other: Self) -> bool {
197 self.end_excl == other.start || other.end_excl == self.start
198 }
199
200 #[inline]
201 pub const fn is_contiguous_with(self, other: Self) -> bool {
202 self.intersects(other) || self.is_adjacent(other)
203 }
204 }
205
206 impl U32CO {
207 #[inline]
208 pub const fn iter(self) -> core::ops::Range<u32> {
209 self.start..self.end_excl
210 }
211
212 #[inline]
213 pub const fn to_range(self) -> core::ops::Range<u32> {
214 self.start..self.end_excl
215 }
216 }
217}
218
219// ------------------------------------------------------------
220// interval algebra api: intersection / convex_hull / between / union / difference / symmetric_difference
221// ------------------------------------------------------------
222
223mod interval_algebra {
224
225 use super::*;
226
227 impl U32CO {
228 /// Returns the intersection of two intervals.
229 ///
230 /// If the intervals do not overlap, returns `None`.
231 #[inline]
232 pub const fn intersection(self, other: Self) -> Option<Self> {
233 let start = if self.start >= other.start {
234 self.start
235 } else {
236 other.start
237 };
238
239 let end_excl = if self.end_excl <= other.end_excl {
240 self.end_excl
241 } else {
242 other.end_excl
243 };
244
245 Self::try_new(start, end_excl)
246 }
247
248 /// Returns the convex hull (smallest interval containing both) of two intervals.
249 ///
250 /// Always returns a valid `U32CO`.
251 #[inline]
252 pub const fn convex_hull(self, other: Self) -> Self {
253 let start = if self.start <= other.start {
254 self.start
255 } else {
256 other.start
257 };
258
259 let end_excl = if self.end_excl >= other.end_excl {
260 self.end_excl
261 } else {
262 other.end_excl
263 };
264
265 Self { start, end_excl }
266 }
267
268 /// Returns the interval strictly between two intervals.
269 ///
270 /// If the intervals are contiguous or overlap, returns `None`.
271 #[inline]
272 pub const fn between(self, other: Self) -> Option<Self> {
273 let (left, right) = if self.start <= other.start {
274 (self, other)
275 } else {
276 (other, self)
277 };
278
279 Self::try_new(left.end_excl, right.start)
280 }
281
282 /// Returns the union of two intervals.
283 ///
284 /// - If intervals are contiguous or overlapping, returns `One` containing the merged interval.
285 /// - Otherwise, returns `Two` containing both intervals in ascending order.
286 #[inline]
287 pub const fn union(self, other: Self) -> OneTwo<Self> {
288 if self.is_contiguous_with(other) {
289 OneTwo::One(self.convex_hull(other))
290 } else if self.start <= other.start {
291 OneTwo::Two(self, other)
292 } else {
293 OneTwo::Two(other, self)
294 }
295 }
296
297 /// Returns the difference of two intervals (self - other).
298 ///
299 /// - If no overlap, returns `One(self)`.
300 /// - If partial overlap, returns `One` or `Two` depending on remaining segments.
301 /// - If fully contained, returns `Zero`.
302 #[inline]
303 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
304 match self.intersection(other) {
305 None => ZeroOneTwo::One(self),
306 Some(inter) => {
307 let left = Self::try_new(self.start, inter.start);
308 let right = Self::try_new(inter.end_excl, self.end_excl);
309
310 match (left, right) {
311 (None, None) => ZeroOneTwo::Zero,
312 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
313 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
314 }
315 }
316 }
317 }
318
319 /// Returns the symmetric difference of two intervals.
320 ///
321 /// Equivalent to `(self - other) ∪ (other - self)`.
322 /// - If intervals do not overlap, returns `Two(self, other)` in order.
323 /// - If intervals partially overlap, returns remaining non-overlapping segments as `One` or `Two`.
324 #[inline]
325 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
326 match self.intersection(other) {
327 None => {
328 if self.start <= other.start {
329 ZeroOneTwo::Two(self, other)
330 } else {
331 ZeroOneTwo::Two(other, self)
332 }
333 }
334 Some(inter) => {
335 let hull = self.convex_hull(other);
336 let left = Self::try_new(hull.start, inter.start);
337 let right = Self::try_new(inter.end_excl, hull.end_excl);
338
339 match (left, right) {
340 (None, None) => ZeroOneTwo::Zero,
341 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
342 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
343 }
344 }
345 }
346 }
347 }
348}
349
350// ------------------------------------------------------------
351// Module: Minkowski arithmetic for U32CO
352// Provides checked and saturating Minkowski operations
353// ------------------------------------------------------------
354
355pub mod minkowski {
356 use super::*;
357
358 pub mod checked {
359 use super::*;
360
361 // --------------------------------------------------------
362 // Interval-to-interval Minkowski operations
363 // --------------------------------------------------------
364 impl U32CO {
365 /// Minkowski addition: [a_start, a_end) + [b_start, b_end)
366 #[inline]
367 pub const fn checked_minkowski_add(self, other: Self) -> Option<Self> {
368 let Some(start) = self.start.checked_add(other.start) else {
369 return None;
370 };
371 let Some(end_excl) = self.end_excl.checked_add(other.end_incl()) else {
372 return None;
373 };
374
375 // SAFETY:
376 // `checked_add` guarantees both bounds are computed without overflow.
377 // For half-open intervals, addition preserves ordering:
378 // self.start <= self.end_excl - 1 and other.start <= other.end_incl(),
379 // therefore `start < end_excl` still holds for the resulting interval.
380 Some(unsafe { Self::new_unchecked(start, end_excl) })
381 }
382
383 /// Minkowski subtraction: [a_start, a_end) - [b_start, b_end)
384 #[inline]
385 pub const fn checked_minkowski_sub(self, other: Self) -> Option<Self> {
386 let Some(start) = self.start.checked_sub(other.end_incl()) else {
387 return None;
388 };
389 let Some(end_excl) = self.end_excl.checked_sub(other.start) else {
390 return None;
391 };
392
393 // SAFETY:
394 // `checked_sub` guarantees both bounds are computed without underflow.
395 // Since `self.start <= self.end_excl - 1` and `other.start <= other.end_incl()`,
396 // we have `self.start - other.end_incl() < self.end_excl - other.start`,
397 // so the resulting half-open interval remains valid.
398 Some(unsafe { Self::new_unchecked(start, end_excl) })
399 }
400
401 /// Minkowski multiplication: [a_start, a_end) * [b_start, b_end)
402 #[inline]
403 pub const fn checked_minkowski_mul_hull(self, other: Self) -> Option<Self> {
404 let Some(start) = self.start.checked_mul(other.start) else {
405 return None;
406 };
407 let Some(end_incl) = self.end_incl().checked_mul(other.end_incl()) else {
408 return None;
409 };
410 let Some(end_excl) = end_incl.checked_add(1) else {
411 return None;
412 };
413
414 // SAFETY:
415 // For `U32CO`, all values are non-negative, so endpoint-wise multiplication
416 // is monotone. `start` is the minimum product and `end_incl` is the maximum.
417 // `checked_add(1)` converts the inclusive upper bound back to half-open form,
418 // and overflow has already been excluded.
419 Some(unsafe { Self::new_unchecked(start, end_excl) })
420 }
421
422 /// Minkowski division: [a_start, a_end) / [b_start, b_end)
423 #[inline]
424 pub const fn checked_minkowski_div_hull(self, other: Self) -> Option<Self> {
425 if other.start == 0 {
426 return None;
427 }
428
429 let Some(start) = self.start.checked_div(other.end_incl()) else {
430 return None;
431 };
432 let Some(end_incl) = self.end_incl().checked_div(other.start) else {
433 return None;
434 };
435 let Some(end_excl) = end_incl.checked_add(1) else {
436 return None;
437 };
438
439 // SAFETY:
440 // `other.start != 0` excludes division by zero, and all operands are unsigned.
441 // Over positive integers, division is monotone with respect to the dividend and
442 // anti-monotone with respect to the divisor, so:
443 // min = self.start / other.end_incl()
444 // max = self.end_incl() / other.start
445 // Thus `start <= end_incl`, and `end_excl = end_incl + 1` is checked.
446 Some(unsafe { Self::new_unchecked(start, end_excl) })
447 }
448 }
449
450 // --------------------------------------------------------
451 // Interval-to-scalar Minkowski operations
452 // --------------------------------------------------------
453 impl U32CO {
454 /// Add a scalar to an interval: [start, end) + n
455 #[inline]
456 pub const fn checked_minkowski_add_scalar(self, n: u32) -> Option<Self> {
457 let Some(start) = self.start.checked_add(n) else {
458 return None;
459 };
460 let Some(end_excl) = self.end_excl.checked_add(n) else {
461 return None;
462 };
463
464 // SAFETY:
465 // `checked_add` excludes overflow, and adding the same scalar to both bounds
466 // preserves the half-open interval ordering.
467 Some(unsafe { Self::new_unchecked(start, end_excl) })
468 }
469
470 /// Subtract a scalar from an interval: [start, end) - n
471 #[inline]
472 pub const fn checked_minkowski_sub_scalar(self, n: u32) -> Option<Self> {
473 let Some(start) = self.start.checked_sub(n) else {
474 return None;
475 };
476 let Some(end_excl) = self.end_excl.checked_sub(n) else {
477 return None;
478 };
479
480 // SAFETY:
481 // `checked_sub` excludes underflow, and subtracting the same scalar from both
482 // bounds preserves the half-open interval ordering.
483 Some(unsafe { Self::new_unchecked(start, end_excl) })
484 }
485
486 /// Multiply an interval by a scalar: [start, end) * n
487 #[inline]
488 pub const fn checked_minkowski_mul_scalar_hull(self, n: u32) -> Option<Self> {
489 let Some(start) = self.start.checked_mul(n) else {
490 return None;
491 };
492 let Some(end_incl) = self.end_incl().checked_mul(n) else {
493 return None;
494 };
495 let Some(end_excl) = end_incl.checked_add(1) else {
496 return None;
497 };
498
499 // SAFETY:
500 // For unsigned integers, multiplication by a scalar is monotone.
501 // Therefore `start * n` is the lower bound and `end_incl * n` is the upper bound.
502 // `checked_*` operations exclude overflow, and `end_excl` restores half-open form.
503 Some(unsafe { Self::new_unchecked(start, end_excl) })
504 }
505
506 /// Divide an interval by a scalar: [start, end) / n
507 #[inline]
508 pub const fn checked_minkowski_div_scalar_hull(self, n: u32) -> Option<Self> {
509 if n == 0 {
510 return None;
511 }
512
513 let start = self.start / n;
514 let end_incl = self.end_incl() / n;
515 let Some(end_excl) = end_incl.checked_add(1) else {
516 return None;
517 };
518
519 // SAFETY:
520 // `n != 0` excludes division by zero. For unsigned integers and positive scalar `n`,
521 // division is monotone, so `self.start / n <= self.end_incl() / n`.
522 // `checked_add(1)` safely converts the inclusive upper bound to half-open form.
523 Some(unsafe { Self::new_unchecked(start, end_excl) })
524 }
525 }
526 }
527
528 pub mod saturating {
529 use super::*;
530
531 // --------------------------------------------------------
532 // Interval-to-interval Minkowski operations
533 // --------------------------------------------------------
534 impl U32CO {
535 #[inline]
536 pub const fn saturating_minkowski_add(self, other: Self) -> Option<Self> {
537 let start = self.start.saturating_add(other.start);
538 let end_excl = self.end_excl.saturating_add(other.end_incl());
539 Self::try_new(start, end_excl)
540 }
541
542 #[inline]
543 pub const fn saturating_minkowski_sub(self, other: Self) -> Option<Self> {
544 let start = self.start.saturating_sub(other.end_incl());
545 let end_excl = self.end_excl.saturating_sub(other.start);
546 Self::try_new(start, end_excl)
547 }
548
549 #[inline]
550 pub const fn saturating_minkowski_mul_hull(self, other: Self) -> Option<Self> {
551 let start = self.start.saturating_mul(other.start);
552 let end_incl = self.end_incl().saturating_mul(other.end_incl());
553 let end_excl = end_incl.saturating_add(1);
554 Self::try_new(start, end_excl)
555 }
556
557 #[inline]
558 pub const fn saturating_minkowski_div_hull(self, other: Self) -> Option<Self> {
559 if other.start == 0 {
560 return None;
561 }
562
563 let start = self.start / other.end_incl();
564 let end_incl = self.end_incl() / other.start;
565 let end_excl = end_incl.saturating_add(1);
566 Self::try_new(start, end_excl)
567 }
568 }
569
570 // --------------------------------------------------------
571 // Interval-to-scalar Minkowski operations
572 // --------------------------------------------------------
573 impl U32CO {
574 /// Saturating add scalar: [start, end) + n
575 #[inline]
576 pub const fn saturating_minkowski_add_scalar(self, n: u32) -> Option<Self> {
577 let start = self.start.saturating_add(n);
578 let end_excl = self.end_excl.saturating_add(n);
579 Self::try_new(start, end_excl)
580 }
581
582 /// Saturating sub scalar: [start, end) - n
583 #[inline]
584 pub const fn saturating_minkowski_sub_scalar(self, n: u32) -> Option<Self> {
585 let start = self.start.saturating_sub(n);
586 let end_excl = self.end_excl.saturating_sub(n);
587 Self::try_new(start, end_excl)
588 }
589
590 /// Saturating mul scalar: [start, end) * n
591 #[inline]
592 pub const fn saturating_minkowski_mul_scalar_hull(self, n: u32) -> Option<Self> {
593 let start = self.start.saturating_mul(n);
594 let end_incl = self.end_incl().saturating_mul(n);
595 let end_excl = end_incl.saturating_add(1);
596 Self::try_new(start, end_excl)
597 }
598
599 /// Saturating div scalar: [start, end) / n
600 #[inline]
601 pub const fn saturating_minkowski_div_scalar_hull(self, n: u32) -> Option<Self> {
602 if n == 0 {
603 return None;
604 }
605
606 let start = self.start / n;
607 let end_incl = self.end_incl() / n;
608 let end_excl = end_incl.saturating_add(1);
609 Self::try_new(start, end_excl)
610 }
611 }
612 }
613}
614
615crate::interval::traits::impl_co_forwarding!(U32CO, u32, u32);