1use crate::res::{OneTwo, ZeroOneTwo};
2
3#[cfg(test)]
4mod between_tests;
5#[cfg(test)]
6mod checked_minkowski_tests;
7#[cfg(test)]
8mod convex_hull_tests;
9#[cfg(test)]
10mod difference_tests;
11#[cfg(test)]
12mod intersection_tests;
13#[cfg(test)]
14mod symmetric_difference_tests;
15#[cfg(test)]
16mod union_tests;
17
18#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
19pub struct I8CO {
20 start: i8,
21 end_excl: i8,
22}
23
24mod construction_accessors_predicates {
28
29 use super::*;
30
31 impl I8CO {
32 #[inline]
33 pub const fn try_new(start: i8, end_excl: i8) -> Option<Self> {
34 if start < end_excl {
35 Some(Self { start, end_excl })
36 } else {
37 None
38 }
39 }
40
41 #[inline]
42 pub(super) const fn new_unchecked(start: i8, end_excl: i8) -> Self {
43 debug_assert!(start < end_excl);
44 Self { start, end_excl }
45 }
46
47 #[inline]
48 pub const fn start(self) -> i8 {
49 self.start
50 }
51
52 #[inline]
53 pub const fn end_excl(self) -> i8 {
54 self.end_excl
55 }
56
57 #[inline]
58 pub const fn end_incl(self) -> i8 {
59 self.end_excl - 1
61 }
62
63 #[inline]
64 pub const fn len(self) -> u8 {
65 (self.end_excl - self.start) as u8
66 }
67
68 #[inline]
69 pub const fn contains(self, x: i8) -> bool {
70 self.start <= x && x < self.end_excl
71 }
72
73 #[inline]
74 pub const fn iter(self) -> core::ops::Range<i8> {
75 self.start..self.end_excl
76 }
77
78 #[inline]
79 pub const fn to_range(self) -> core::ops::Range<i8> {
80 self.start..self.end_excl
81 }
82
83 #[inline]
84 pub const fn intersects(self, other: Self) -> bool {
85 !(self.end_excl <= other.start || other.end_excl <= self.start)
86 }
87
88 #[inline]
89 pub const fn is_adjacent(self, other: Self) -> bool {
90 self.end_excl == other.start || other.end_excl == self.start
91 }
92
93 #[inline]
94 pub const fn is_contiguous_with(self, other: Self) -> bool {
95 self.intersects(other) || self.is_adjacent(other)
96 }
97 }
98}
99mod interval_algebra {
104
105 use super::*;
106
107 impl I8CO {
108 #[inline]
112 pub const fn intersection(self, other: Self) -> Option<Self> {
113 let start = if self.start >= other.start {
114 self.start
115 } else {
116 other.start
117 };
118
119 let end_excl = if self.end_excl <= other.end_excl {
120 self.end_excl
121 } else {
122 other.end_excl
123 };
124
125 Self::try_new(start, end_excl)
126 }
127
128 #[inline]
132 pub const fn convex_hull(self, other: Self) -> Self {
133 let start = if self.start <= other.start {
134 self.start
135 } else {
136 other.start
137 };
138
139 let end_excl = if self.end_excl >= other.end_excl {
140 self.end_excl
141 } else {
142 other.end_excl
143 };
144
145 Self { start, end_excl }
146 }
147
148 #[inline]
152 pub const fn between(self, other: Self) -> Option<Self> {
153 let (left, right) = if self.start <= other.start {
154 (self, other)
155 } else {
156 (other, self)
157 };
158
159 Self::try_new(left.end_excl, right.start)
160 }
161
162 #[inline]
167 pub const fn union(self, other: Self) -> OneTwo<Self> {
168 if self.is_contiguous_with(other) {
169 OneTwo::One(self.convex_hull(other))
170 } else if self.start <= other.start {
171 OneTwo::Two(self, other)
172 } else {
173 OneTwo::Two(other, self)
174 }
175 }
176
177 #[inline]
183 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
184 match self.intersection(other) {
185 None => ZeroOneTwo::One(self),
186 Some(inter) => {
187 let left = Self::try_new(self.start, inter.start);
188 let right = Self::try_new(inter.end_excl, self.end_excl);
189
190 match (left, right) {
191 (None, None) => ZeroOneTwo::Zero,
192 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
193 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
194 }
195 }
196 }
197 }
198
199 #[inline]
205 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
206 match self.intersection(other) {
207 None => {
208 if self.start <= other.start {
209 ZeroOneTwo::Two(self, other)
210 } else {
211 ZeroOneTwo::Two(other, self)
212 }
213 }
214 Some(inter) => {
215 let hull = self.convex_hull(other);
216 let left = Self::try_new(hull.start, inter.start);
217 let right = Self::try_new(inter.end_excl, hull.end_excl);
218
219 match (left, right) {
220 (None, None) => ZeroOneTwo::Zero,
221 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
222 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
223 }
224 }
225 }
226 }
227 }
228}
229
230pub mod minkowski {
236 use super::*;
237
238 type Min = i8;
239 type Max = i8;
240
241 #[inline]
242 const fn min_max4(a: i8, b: i8, c: i8, d: i8) -> (Min, Max) {
243 let (min1, max1) = if a < b { (a, b) } else { (b, a) };
244 let (min2, max2) = if c < d { (c, d) } else { (d, c) };
245 let min = if min1 < min2 { min1 } else { min2 };
246 let max = if max1 > max2 { max1 } else { max2 };
247 (min, max)
248 }
249
250 #[inline]
251 const fn min_max2(a: i8, b: i8) -> (Min, Max) {
252 if a < b { (a, b) } else { (b, a) }
253 }
254
255 pub mod checked {
256 use super::*;
257
258 impl I8CO {
262 #[inline]
263 pub const fn checked_minkowski_add(self, other: Self) -> Option<Self> {
264 let Some(start) = self.start.checked_add(other.start) else {
265 return None;
266 };
267 let Some(end_excl) = self.end_excl.checked_add(other.end_incl()) else {
268 return None;
269 };
270 Some(Self::new_unchecked(start, end_excl))
271 }
272
273 #[inline]
274 pub const fn checked_minkowski_sub(self, other: Self) -> Option<Self> {
275 let Some(start) = self.start.checked_sub(other.end_incl()) else {
276 return None;
277 };
278 let Some(end_excl) = self.end_excl.checked_sub(other.start) else {
279 return None;
280 };
281 Some(Self::new_unchecked(start, end_excl))
282 }
283
284 #[inline]
285 pub const fn checked_minkowski_mul(self, other: Self) -> Option<Self> {
286 let a = self.start;
287 let b = self.end_incl();
288 let c = other.start;
289 let d = other.end_incl();
290
291 let Some(p1) = a.checked_mul(c) else {
292 return None;
293 };
294 let Some(p2) = a.checked_mul(d) else {
295 return None;
296 };
297 let Some(p3) = b.checked_mul(c) else {
298 return None;
299 };
300 let Some(p4) = b.checked_mul(d) else {
301 return None;
302 };
303
304 let (start, end_incl) = min_max4(p1, p2, p3, p4);
305
306 let Some(end_excl) = end_incl.checked_add(1) else {
307 return None;
308 };
309
310 Some(Self::new_unchecked(start, end_excl))
311 }
312
313 #[inline]
314 pub const fn checked_minkowski_div(self, other: Self) -> Option<Self> {
315 if other.start <= 0 && other.end_incl() >= 0 {
316 return None;
317 }
318
319 let a = self.start;
320 let b = self.end_incl();
321 let c = other.start;
322 let d = other.end_incl();
323
324 let Some(p1) = a.checked_div(c) else {
325 return None;
326 };
327 let Some(p2) = a.checked_div(d) else {
328 return None;
329 };
330 let Some(p3) = b.checked_div(c) else {
331 return None;
332 };
333 let Some(p4) = b.checked_div(d) else {
334 return None;
335 };
336
337 let (start, end_incl) = min_max4(p1, p2, p3, p4);
338
339 let Some(end_excl) = end_incl.checked_add(1) else {
340 return None;
341 };
342
343 Some(Self::new_unchecked(start, end_excl))
344 }
345 }
346
347 impl I8CO {
351 #[inline]
352 pub const fn checked_minkowski_add_n(self, n: i8) -> Option<Self> {
353 let Some(start) = self.start.checked_add(n) else {
354 return None;
355 };
356 let Some(end_excl) = self.end_excl.checked_add(n) else {
357 return None;
358 };
359 Some(Self::new_unchecked(start, end_excl))
360 }
361
362 #[inline]
363 pub const fn checked_minkowski_sub_n(self, n: i8) -> Option<Self> {
364 let Some(start) = self.start.checked_sub(n) else {
365 return None;
366 };
367 let Some(end_excl) = self.end_excl.checked_sub(n) else {
368 return None;
369 };
370 Some(Self::new_unchecked(start, end_excl))
371 }
372
373 #[inline]
374 pub const fn checked_minkowski_mul_n(self, n: i8) -> Option<Self> {
375 let Some(a) = self.start.checked_mul(n) else {
376 return None;
377 };
378 let Some(b) = self.end_incl().checked_mul(n) else {
379 return None;
380 };
381
382 let (start, end_incl) = min_max2(a, b);
383
384 let Some(end_excl) = end_incl.checked_add(1) else {
385 return None;
386 };
387 Some(Self::new_unchecked(start, end_excl))
388 }
389
390 #[inline]
391 pub const fn checked_minkowski_div_n(self, n: i8) -> Option<Self> {
392 if n == 0 {
393 return None;
394 }
395 let Some(a) = self.start.checked_div(n) else {
396 return None;
397 };
398 let Some(b) = self.end_incl().checked_div(n) else {
399 return None;
400 };
401
402 let (start, end_incl) = min_max2(a, b);
403
404 let Some(end_excl) = end_incl.checked_add(1) else {
405 return None;
406 };
407 Some(Self::new_unchecked(start, end_excl))
408 }
409 }
410 }
411
412 pub mod saturating {
416 use super::*;
417
418 impl I8CO {
419 #[inline]
420 pub const fn saturating_minkowski_add(self, other: Self) -> Option<Self> {
421 let start = self.start.saturating_add(other.start);
422 let end_excl = self.end_excl.saturating_add(other.end_incl());
423 Self::try_new(start, end_excl)
424 }
425
426 #[inline]
427 pub const fn saturating_minkowski_sub(self, other: Self) -> Option<Self> {
428 let start = self.start.saturating_sub(other.end_incl());
429 let end_excl = self.end_excl.saturating_sub(other.start);
430 Self::try_new(start, end_excl)
431 }
432
433 #[inline]
434 pub const fn saturating_minkowski_mul(self, other: Self) -> Option<Self> {
435 let a = self.start.saturating_mul(other.start);
436 let b = self.start.saturating_mul(other.end_incl());
437 let c = self.end_incl().saturating_mul(other.start);
438 let d = self.end_incl().saturating_mul(other.end_incl());
439
440 let (start, end_incl) = min_max4(a, b, c, d);
441
442 let end_excl = end_incl.saturating_add(1);
443 Self::try_new(start, end_excl)
444 }
445
446 #[inline]
447 pub const fn saturating_minkowski_div(self, other: Self) -> Option<Self> {
448 if other.start <= 0 && other.end_incl() >= 0 {
449 return None;
450 }
451
452 let a = self.start / other.start;
453 let b = self.start / other.end_incl();
454 let c = self.end_incl() / other.start;
455 let d = self.end_incl() / other.end_incl();
456
457 let (start, end_incl) = min_max4(a, b, c, d);
458
459 let end_excl = end_incl.saturating_add(1);
460 Self::try_new(start, end_excl)
461 }
462 }
463
464 impl I8CO {
465 #[inline]
466 pub const fn saturating_minkowski_add_n(self, n: i8) -> Option<Self> {
467 let start = self.start.saturating_add(n);
468 let end_excl = self.end_excl.saturating_add(n);
469 Self::try_new(start, end_excl)
470 }
471
472 #[inline]
473 pub const fn saturating_minkowski_sub_n(self, n: i8) -> Option<Self> {
474 let start = self.start.saturating_sub(n);
475 let end_excl = self.end_excl.saturating_sub(n);
476 Self::try_new(start, end_excl)
477 }
478
479 #[inline]
480 pub const fn saturating_minkowski_mul_n(self, n: i8) -> Option<Self> {
481 let a = self.start.saturating_mul(n);
482 let b = self.end_incl().saturating_mul(n);
483
484 let (start, end_incl) = min_max2(a, b);
485
486 let end_excl = end_incl.saturating_add(1);
487 Self::try_new(start, end_excl)
488 }
489
490 #[inline]
491 pub const fn saturating_minkowski_div_n(self, n: i8) -> Option<Self> {
492 if n == 0 {
493 return None;
494 }
495
496 let a = self.start / n;
497 let b = self.end_incl() / n;
498
499 let (start, end_incl) = min_max2(a, b);
500
501 let end_excl = end_incl.saturating_add(1);
502 Self::try_new(start, end_excl)
503 }
504 }
505 }
506}