1use crate::res::{OneTwo, ZeroOneTwo};
2
3#[cfg(test)]
4mod between_tests;
5#[cfg(test)]
6mod convex_hull_tests;
7#[cfg(test)]
8mod difference_tests;
9#[cfg(test)]
10mod intersection_tests;
11#[cfg(test)]
12mod minkowski_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 intersects(self, other: Self) -> bool {
80 !(self.end_excl <= other.start || other.end_excl <= self.start)
81 }
82
83 #[inline]
84 pub const fn is_adjacent(self, other: Self) -> bool {
85 self.end_excl == other.start || other.end_excl == self.start
86 }
87
88 #[inline]
89 pub const fn is_contiguous_with(self, other: Self) -> bool {
90 self.intersects(other) || self.is_adjacent(other)
91 }
92 }
93}
94mod interval_algebra {
99
100 use super::*;
101
102 impl I8CO {
103 #[inline]
107 pub const fn intersection(self, other: Self) -> Option<Self> {
108 let start = if self.start >= other.start {
109 self.start
110 } else {
111 other.start
112 };
113
114 let end_excl = if self.end_excl <= other.end_excl {
115 self.end_excl
116 } else {
117 other.end_excl
118 };
119
120 Self::try_new(start, end_excl)
121 }
122
123 #[inline]
127 pub const fn convex_hull(self, other: Self) -> Self {
128 let start = if self.start <= other.start {
129 self.start
130 } else {
131 other.start
132 };
133
134 let end_excl = if self.end_excl >= other.end_excl {
135 self.end_excl
136 } else {
137 other.end_excl
138 };
139
140 Self { start, end_excl }
141 }
142
143 #[inline]
147 pub const fn between(self, other: Self) -> Option<Self> {
148 let (left, right) = if self.start <= other.start {
149 (self, other)
150 } else {
151 (other, self)
152 };
153
154 Self::try_new(left.end_excl, right.start)
155 }
156
157 #[inline]
162 pub const fn union(self, other: Self) -> OneTwo<Self> {
163 if self.is_contiguous_with(other) {
164 OneTwo::One(self.convex_hull(other))
165 } else if self.start <= other.start {
166 OneTwo::Two(self, other)
167 } else {
168 OneTwo::Two(other, self)
169 }
170 }
171
172 #[inline]
178 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
179 match self.intersection(other) {
180 None => ZeroOneTwo::One(self),
181 Some(inter) => {
182 let left = Self::try_new(self.start, inter.start);
183 let right = Self::try_new(inter.end_excl, self.end_excl);
184
185 match (left, right) {
186 (None, None) => ZeroOneTwo::Zero,
187 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
188 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
189 }
190 }
191 }
192 }
193
194 #[inline]
200 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
201 match self.intersection(other) {
202 None => {
203 if self.start <= other.start {
204 ZeroOneTwo::Two(self, other)
205 } else {
206 ZeroOneTwo::Two(other, self)
207 }
208 }
209 Some(inter) => {
210 let hull = self.convex_hull(other);
211 let left = Self::try_new(hull.start, inter.start);
212 let right = Self::try_new(inter.end_excl, hull.end_excl);
213
214 match (left, right) {
215 (None, None) => ZeroOneTwo::Zero,
216 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
217 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
218 }
219 }
220 }
221 }
222 }
223}
224
225pub mod minkowski {
231 use super::I8CO;
232
233 impl I8CO {
237 #[inline]
239 pub const fn minkowski_add(self, other: Self) -> Option<Self> {
240 match self.start.checked_add(other.start) {
241 Some(start) => match self.end_incl().checked_add(other.end_incl()) {
242 Some(end_incl) => match end_incl.checked_add(1) {
243 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
244 None => None,
245 },
246 None => None,
247 },
248 None => None,
249 }
250 }
251
252 #[inline]
254 pub const fn minkowski_sub(self, other: Self) -> Option<Self> {
255 match self.start.checked_sub(other.end_incl()) {
256 Some(start) => match self.end_incl().checked_sub(other.start) {
257 Some(end_incl) => match end_incl.checked_add(1) {
258 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
259 None => None,
260 },
261 None => None,
262 },
263 None => None,
264 }
265 }
266
267 #[inline]
269 pub const fn minkowski_mul(self, other: Self) -> Option<Self> {
270 let a = self.start;
271 let b = self.end_incl();
272 let c = other.start;
273 let d = other.end_incl();
274
275 match a.checked_mul(c) {
276 Some(p1) => match a.checked_mul(d) {
277 Some(p2) => match b.checked_mul(c) {
278 Some(p3) => match b.checked_mul(d) {
279 Some(p4) => {
280 let (min1, max1) = if p1 < p2 { (p1, p2) } else { (p2, p1) };
281 let (min2, max2) = if p3 < p4 { (p3, p4) } else { (p4, p3) };
282 let min = if min1 < min2 { min1 } else { min2 };
283 let max = if max1 > max2 { max1 } else { max2 };
284 match max.checked_add(1) {
285 Some(end_excl) => Some(Self::new_unchecked(min, end_excl)),
286 None => None,
287 }
288 }
289 None => None,
290 },
291 None => None,
292 },
293 None => None,
294 },
295 None => None,
296 }
297 }
298
299 #[inline]
301 pub const fn minkowski_div(self, other: Self) -> Option<Self> {
302 if other.start <= 0 && other.end_incl() >= 0 {
303 return None; }
305
306 let a = self.start;
307 let b = self.end_incl();
308 let c = other.start;
309 let d = other.end_incl();
310
311 match a.checked_div(c) {
312 Some(p1) => match a.checked_div(d) {
313 Some(p2) => match b.checked_div(c) {
314 Some(p3) => match b.checked_div(d) {
315 Some(p4) => {
316 let (min1, max1) = if p1 < p2 { (p1, p2) } else { (p2, p1) };
317 let (min2, max2) = if p3 < p4 { (p3, p4) } else { (p4, p3) };
318 let min = if min1 < min2 { min1 } else { min2 };
319 let max = if max1 > max2 { max1 } else { max2 };
320 match max.checked_add(1) {
321 Some(end_excl) => Some(Self::new_unchecked(min, end_excl)),
322 None => None,
323 }
324 }
325 None => None,
326 },
327 None => None,
328 },
329 None => None,
330 },
331 None => None,
332 }
333 }
334 }
335
336 impl I8CO {
340 #[inline]
342 pub const fn minkowski_add_n(self, n: i8) -> Option<Self> {
343 match self.start.checked_add(n) {
344 Some(start) => match self.end_excl.checked_add(n) {
345 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
346 None => None,
347 },
348 None => None,
349 }
350 }
351
352 #[inline]
354 pub const fn minkowski_sub_n(self, n: i8) -> Option<Self> {
355 match self.start.checked_sub(n) {
356 Some(start) => match self.end_excl.checked_sub(n) {
357 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
358 None => None,
359 },
360 None => None,
361 }
362 }
363
364 #[inline]
366 pub const fn minkowski_mul_n(self, n: i8) -> Option<Self> {
367 match self.start.checked_mul(n) {
368 Some(a) => match self.end_incl().checked_mul(n) {
369 Some(b) => {
370 let (min, max) = match a < b {
371 true => (a, b),
372 false => (b, a),
373 };
374 match max.checked_add(1) {
375 Some(end_excl) => Some(Self::new_unchecked(min, end_excl)),
376 None => None,
377 }
378 }
379 None => None,
380 },
381 None => None,
382 }
383 }
384
385 #[inline]
387 pub const fn minkowski_div_n(self, n: i8) -> Option<Self> {
388 match n {
389 0 => None, _ => match self.start.checked_div(n) {
391 Some(a) => match self.end_incl().checked_div(n) {
392 Some(b) => {
393 let (min, max) = match a < b {
394 true => (a, b),
395 false => (b, a),
396 };
397 match max.checked_add(1) {
398 Some(end_excl) => Some(Self::new_unchecked(min, end_excl)),
399 None => None,
400 }
401 }
402 None => None,
403 },
404 None => None,
405 },
406 }
407 }
408 }
409}