Skip to main content

int_interval/
i32.rs

1// -----------------------------------------------------------------------------
2// @generated by xtask/codegen (signed)
3// DO NOT EDIT MANUALLY.
4// Changes will be overwritten.
5// -----------------------------------------------------------------------------
6
7use crate::res::{OneTwo, ZeroOneTwo};
8
9#[cfg(test)]
10mod between_tests;
11#[cfg(test)]
12mod convex_hull_tests;
13#[cfg(test)]
14mod difference_tests;
15#[cfg(test)]
16mod intersection_tests;
17#[cfg(test)]
18mod symmetric_difference_tests;
19#[cfg(test)]
20mod transform_tests;
21#[cfg(test)]
22mod union_tests;
23
24#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
25pub struct I32CO {
26    start: i32,
27    end_excl: i32,
28}
29
30// ------------------------------------------------------------
31// low-level api: construction / accessors / predicates
32// ------------------------------------------------------------
33mod construction_accessors_predicates {
34
35    use super::*;
36
37    impl I32CO {
38        #[inline]
39        pub const fn try_new(start: i32, end_excl: i32) -> Option<Self> {
40            if start < end_excl {
41                Some(Self { start, end_excl })
42            } else {
43                None
44            }
45        }
46
47        #[inline]
48        pub(super) const fn new_unchecked(start: i32, end_excl: i32) -> Self {
49            debug_assert!(start < end_excl);
50            Self { start, end_excl }
51        }
52
53        #[inline]
54        pub const fn start(self) -> i32 {
55            self.start
56        }
57
58        #[inline]
59        pub const fn end_excl(self) -> i32 {
60            self.end_excl
61        }
62
63        #[inline]
64        pub const fn end_incl(self) -> i32 {
65            // i32_low_bound =< start < end_excl
66            self.end_excl - 1
67        }
68
69        #[inline]
70        pub const fn len(self) -> u32 {
71            (self.end_excl - self.start) as u32
72        }
73
74        #[inline]
75        pub const fn contains(self, x: i32) -> bool {
76            self.start <= x && x < self.end_excl
77        }
78
79        #[inline]
80        pub const fn iter(self) -> core::ops::Range<i32> {
81            self.start..self.end_excl
82        }
83
84        #[inline]
85        pub const fn intersects(self, other: Self) -> bool {
86            !(self.end_excl <= other.start || other.end_excl <= self.start)
87        }
88
89        #[inline]
90        pub const fn is_adjacent(self, other: Self) -> bool {
91            self.end_excl == other.start || other.end_excl == self.start
92        }
93
94        #[inline]
95        pub const fn is_contiguous_with(self, other: Self) -> bool {
96            self.intersects(other) || self.is_adjacent(other)
97        }
98    }
99}
100// ------------------------------------------------------------
101// interval algebra api: intersection / convex_hull / between / union / difference / symmetric_difference
102// ------------------------------------------------------------
103
104mod interval_algebra {
105
106    use super::*;
107
108    impl I32CO {
109        /// Returns the intersection of two intervals.
110        ///
111        /// If the intervals do not overlap, returns `None`.
112        #[inline]
113        pub const fn intersection(self, other: Self) -> Option<Self> {
114            let start = if self.start >= other.start {
115                self.start
116            } else {
117                other.start
118            };
119
120            let end_excl = if self.end_excl <= other.end_excl {
121                self.end_excl
122            } else {
123                other.end_excl
124            };
125
126            Self::try_new(start, end_excl)
127        }
128
129        /// Returns the convex hull (smallest interval containing both) of two intervals.
130        ///
131        /// Always returns a valid `I32CO`.
132        #[inline]
133        pub const fn convex_hull(self, other: Self) -> Self {
134            let start = if self.start <= other.start {
135                self.start
136            } else {
137                other.start
138            };
139
140            let end_excl = if self.end_excl >= other.end_excl {
141                self.end_excl
142            } else {
143                other.end_excl
144            };
145
146            Self { start, end_excl }
147        }
148
149        /// Returns the interval strictly between two intervals.
150        ///
151        /// If the intervals are contiguous or overlap, returns `None`.
152        #[inline]
153        pub const fn between(self, other: Self) -> Option<Self> {
154            let (left, right) = if self.start <= other.start {
155                (self, other)
156            } else {
157                (other, self)
158            };
159
160            Self::try_new(left.end_excl, right.start)
161        }
162
163        /// Returns the union of two intervals.
164        ///
165        /// - If intervals are contiguous or overlapping, returns `One` containing the merged interval.
166        /// - Otherwise, returns `Two` containing both intervals in ascending order.
167        #[inline]
168        pub const fn union(self, other: Self) -> OneTwo<Self> {
169            if self.is_contiguous_with(other) {
170                OneTwo::One(self.convex_hull(other))
171            } else if self.start <= other.start {
172                OneTwo::Two(self, other)
173            } else {
174                OneTwo::Two(other, self)
175            }
176        }
177
178        /// Returns the difference of two intervals (self - other).
179        ///
180        /// - If no overlap, returns `One(self)`.
181        /// - If partial overlap, returns `One` or `Two` depending on remaining segments.
182        /// - If fully contained, returns `Zero`.
183        #[inline]
184        pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
185            match self.intersection(other) {
186                None => ZeroOneTwo::One(self),
187                Some(inter) => {
188                    let left = Self::try_new(self.start, inter.start);
189                    let right = Self::try_new(inter.end_excl, self.end_excl);
190
191                    match (left, right) {
192                        (None, None) => ZeroOneTwo::Zero,
193                        (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
194                        (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
195                    }
196                }
197            }
198        }
199
200        /// Returns the symmetric difference of two intervals.
201        ///
202        /// Equivalent to `(self - other) ∪ (other - self)`.
203        /// - If intervals do not overlap, returns `Two(self, other)` in order.
204        /// - If intervals partially overlap, returns remaining non-overlapping segments as `One` or `Two`.
205        #[inline]
206        pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
207            match self.intersection(other) {
208                None => {
209                    if self.start <= other.start {
210                        ZeroOneTwo::Two(self, other)
211                    } else {
212                        ZeroOneTwo::Two(other, self)
213                    }
214                }
215                Some(inter) => {
216                    let hull = self.convex_hull(other);
217                    let left = Self::try_new(hull.start, inter.start);
218                    let right = Self::try_new(inter.end_excl, hull.end_excl);
219
220                    match (left, right) {
221                        (None, None) => ZeroOneTwo::Zero,
222                        (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
223                        (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
224                    }
225                }
226            }
227        }
228    }
229}
230
231// ------------------------------------------------------------
232// interval arithmetic / transform api: scale / shift
233// ------------------------------------------------------------
234
235mod interval_arithmetic {
236    use super::I32CO;
237
238    impl I32CO {
239        #[inline]
240        pub const fn scale(self, factor: i32) -> Option<Self> {
241            if factor == 0 {
242                return None;
243            }
244
245            let s0 = match self.start.checked_mul(factor) {
246                Some(v) => v,
247                None => return None,
248            };
249
250            let s1 = match self.end_excl.checked_mul(factor) {
251                Some(v) => v,
252                None => return None,
253            };
254
255            if s0 < s1 {
256                Some(I32CO::new_unchecked(s0, s1))
257            } else {
258                Some(I32CO::new_unchecked(s1, s0))
259            }
260        }
261
262        #[inline]
263        pub const fn shift(self, offset: i32) -> Option<Self> {
264            let a = match self.start.checked_add(offset) {
265                Some(v) => v,
266                None => return None,
267            };
268
269            let b = match self.end_excl.checked_add(offset) {
270                Some(v) => v,
271                None => return None,
272            };
273
274            Some(I32CO::new_unchecked(a, b))
275        }
276    }
277}