1use 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 minkowski_tests;
21#[cfg(test)]
22mod union_tests;
23
24#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
25pub struct UsizeCO {
26 start: usize,
27 end_excl: usize,
28}
29
30mod construction_accessors_predicates {
35
36 use super::*;
37
38 impl UsizeCO {
39 #[inline]
40 pub const fn try_new(start: usize, end_excl: usize) -> Option<Self> {
41 if start < end_excl {
42 Some(Self { start, end_excl })
43 } else {
44 None
45 }
46 }
47
48 #[inline]
49 pub(super) const fn new_unchecked(start: usize, end_excl: usize) -> Self {
50 debug_assert!(start < end_excl);
51 Self { start, end_excl }
52 }
53
54 #[inline]
55 pub const fn start(self) -> usize {
56 self.start
57 }
58
59 #[inline]
60 pub const fn end_excl(self) -> usize {
61 self.end_excl
62 }
63
64 #[inline]
65 pub const fn end_incl(self) -> usize {
66 self.end_excl - 1
68 }
69
70 #[inline]
71 pub const fn len(self) -> usize {
72 self.end_excl - self.start
73 }
74
75 #[inline]
76 pub const fn contains(self, x: usize) -> bool {
77 self.start <= x && x < self.end_excl
78 }
79
80 #[inline]
81 pub const fn iter(self) -> core::ops::Range<usize> {
82 self.start..self.end_excl
83 }
84
85 #[inline]
86 pub const fn intersects(self, other: Self) -> bool {
87 !(self.end_excl <= other.start || other.end_excl <= self.start)
88 }
89
90 #[inline]
91 pub const fn is_adjacent(self, other: Self) -> bool {
92 self.end_excl == other.start || other.end_excl == self.start
93 }
94
95 #[inline]
96 pub const fn is_contiguous_with(self, other: Self) -> bool {
97 self.intersects(other) || self.is_adjacent(other)
98 }
99 }
100}
101
102mod interval_algebra {
107
108 use super::*;
109
110 impl UsizeCO {
111 #[inline]
115 pub const fn intersection(self, other: Self) -> Option<Self> {
116 let start = if self.start >= other.start {
117 self.start
118 } else {
119 other.start
120 };
121
122 let end_excl = if self.end_excl <= other.end_excl {
123 self.end_excl
124 } else {
125 other.end_excl
126 };
127
128 Self::try_new(start, end_excl)
129 }
130
131 #[inline]
135 pub const fn convex_hull(self, other: Self) -> Self {
136 let start = if self.start <= other.start {
137 self.start
138 } else {
139 other.start
140 };
141
142 let end_excl = if self.end_excl >= other.end_excl {
143 self.end_excl
144 } else {
145 other.end_excl
146 };
147
148 Self { start, end_excl }
149 }
150
151 #[inline]
155 pub const fn between(self, other: Self) -> Option<Self> {
156 let (left, right) = if self.start <= other.start {
157 (self, other)
158 } else {
159 (other, self)
160 };
161
162 Self::try_new(left.end_excl, right.start)
163 }
164
165 #[inline]
170 pub const fn union(self, other: Self) -> OneTwo<Self> {
171 if self.is_contiguous_with(other) {
172 OneTwo::One(self.convex_hull(other))
173 } else if self.start <= other.start {
174 OneTwo::Two(self, other)
175 } else {
176 OneTwo::Two(other, self)
177 }
178 }
179
180 #[inline]
186 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
187 match self.intersection(other) {
188 None => ZeroOneTwo::One(self),
189 Some(inter) => {
190 let left = Self::try_new(self.start, inter.start);
191 let right = Self::try_new(inter.end_excl, self.end_excl);
192
193 match (left, right) {
194 (None, None) => ZeroOneTwo::Zero,
195 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
196 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
197 }
198 }
199 }
200 }
201
202 #[inline]
208 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
209 match self.intersection(other) {
210 None => {
211 if self.start <= other.start {
212 ZeroOneTwo::Two(self, other)
213 } else {
214 ZeroOneTwo::Two(other, self)
215 }
216 }
217 Some(inter) => {
218 let hull = self.convex_hull(other);
219 let left = Self::try_new(hull.start, inter.start);
220 let right = Self::try_new(inter.end_excl, hull.end_excl);
221
222 match (left, right) {
223 (None, None) => ZeroOneTwo::Zero,
224 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
225 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
226 }
227 }
228 }
229 }
230 }
231}
232
233pub mod minkowski {
239 use super::UsizeCO;
240
241 impl UsizeCO {
245 #[inline]
247 pub const fn minkowski_add(self, other: Self) -> Option<Self> {
248 match self.start.checked_add(other.start) {
249 Some(start) => match self.end_incl().checked_add(other.end_incl()) {
250 Some(end_incl) => match end_incl.checked_add(1) {
251 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
252 None => None,
253 },
254 None => None,
255 },
256 None => None,
257 }
258 }
259
260 #[inline]
262 pub const fn minkowski_sub(self, other: Self) -> Option<Self> {
263 match self.start.checked_sub(other.end_incl()) {
264 Some(start) => match self.end_incl().checked_sub(other.start) {
265 Some(end_incl) => match end_incl.checked_add(1) {
266 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
267 None => None,
268 },
269 None => None,
270 },
271 None => None,
272 }
273 }
274
275 #[inline]
277 pub const fn minkowski_mul(self, other: Self) -> Option<Self> {
278 match self.start.checked_mul(other.start) {
279 Some(start) => match self.end_incl().checked_mul(other.end_incl()) {
280 Some(end_incl) => match end_incl.checked_add(1) {
281 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
282 None => None,
283 },
284 None => None,
285 },
286 None => None,
287 }
288 }
289
290 #[inline]
292 pub const fn minkowski_div(self, other: Self) -> Option<Self> {
293 if other.start == 0 {
294 return None; }
296 match self.start.checked_div(other.end_incl()) {
297 Some(start) => match self.end_incl().checked_div(other.start) {
298 Some(end_incl) => match end_incl.checked_add(1) {
299 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
300 None => None,
301 },
302 None => None,
303 },
304 None => None,
305 }
306 }
307 }
308
309 impl UsizeCO {
313 #[inline]
315 pub const fn minkowski_add_n(self, n: usize) -> Option<Self> {
316 match self.start.checked_add(n) {
317 Some(start) => match self.end_excl.checked_add(n) {
318 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
319 None => None,
320 },
321 None => None,
322 }
323 }
324
325 #[inline]
327 pub const fn minkowski_sub_n(self, n: usize) -> Option<Self> {
328 match self.start.checked_sub(n) {
329 Some(start) => match self.end_excl.checked_sub(n) {
330 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
331 None => None,
332 },
333 None => None,
334 }
335 }
336
337 #[inline]
339 pub const fn minkowski_mul_n(self, n: usize) -> Option<Self> {
340 match self.start.checked_mul(n) {
341 Some(start) => match self.end_incl().checked_mul(n) {
342 Some(end_incl) => match end_incl.checked_add(1) {
343 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
344 None => None,
345 },
346 None => None,
347 },
348 None => None,
349 }
350 }
351
352 #[inline]
354 pub const fn minkowski_div_n(self, n: usize) -> Option<Self> {
355 if n == 0 {
356 return None; }
358 let start = self.start / n;
359 let end_incl = self.end_incl() / n;
360 match end_incl.checked_add(1) {
361 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
362 None => None,
363 }
364 }
365 }
366}