Skip to main content

int_interval/
u16.rs

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