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 saturating_minkowski_tests;
15#[cfg(test)]
16mod symmetric_difference_tests;
17#[cfg(test)]
18mod union_tests;
19
20#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
21pub struct U8CO {
22 start: u8,
23 end_excl: u8,
24}
25
26mod construction_accessors_predicates {
31
32 use super::*;
33
34 impl U8CO {
35 #[inline]
36 pub const fn try_new(start: u8, end_excl: u8) -> Option<Self> {
37 if start < end_excl {
38 Some(Self { start, end_excl })
39 } else {
40 None
41 }
42 }
43
44 #[inline]
45 pub(super) const fn new_unchecked(start: u8, end_excl: u8) -> Self {
46 debug_assert!(start < end_excl);
47 Self { start, end_excl }
48 }
49
50 #[inline]
51 pub const fn start(self) -> u8 {
52 self.start
53 }
54
55 #[inline]
56 pub const fn end_excl(self) -> u8 {
57 self.end_excl
58 }
59
60 #[inline]
61 pub const fn end_incl(self) -> u8 {
62 self.end_excl - 1
64 }
65
66 #[inline]
67 pub const fn len(self) -> u8 {
68 self.end_excl - self.start
69 }
70
71 #[inline]
72 pub const fn contains(self, x: u8) -> bool {
73 self.start <= x && x < self.end_excl
74 }
75
76 #[inline]
77 pub const fn iter(self) -> core::ops::Range<u8> {
78 self.start..self.end_excl
79 }
80
81 #[inline]
82 pub const fn to_range(self) -> core::ops::Range<u8> {
83 self.start..self.end_excl
84 }
85
86 #[inline]
87 pub const fn intersects(self, other: Self) -> bool {
88 !(self.end_excl <= other.start || other.end_excl <= self.start)
89 }
90
91 #[inline]
92 pub const fn is_adjacent(self, other: Self) -> bool {
93 self.end_excl == other.start || other.end_excl == self.start
94 }
95
96 #[inline]
97 pub const fn is_contiguous_with(self, other: Self) -> bool {
98 self.intersects(other) || self.is_adjacent(other)
99 }
100 }
101}
102
103mod interval_algebra {
108
109 use super::*;
110
111 impl U8CO {
112 #[inline]
116 pub const fn intersection(self, other: Self) -> Option<Self> {
117 let start = if self.start >= other.start {
118 self.start
119 } else {
120 other.start
121 };
122
123 let end_excl = if self.end_excl <= other.end_excl {
124 self.end_excl
125 } else {
126 other.end_excl
127 };
128
129 Self::try_new(start, end_excl)
130 }
131
132 #[inline]
136 pub const fn convex_hull(self, other: Self) -> Self {
137 let start = if self.start <= other.start {
138 self.start
139 } else {
140 other.start
141 };
142
143 let end_excl = if self.end_excl >= other.end_excl {
144 self.end_excl
145 } else {
146 other.end_excl
147 };
148
149 Self { start, end_excl }
150 }
151
152 #[inline]
156 pub const fn between(self, other: Self) -> Option<Self> {
157 let (left, right) = if self.start <= other.start {
158 (self, other)
159 } else {
160 (other, self)
161 };
162
163 Self::try_new(left.end_excl, right.start)
164 }
165
166 #[inline]
171 pub const fn union(self, other: Self) -> OneTwo<Self> {
172 if self.is_contiguous_with(other) {
173 OneTwo::One(self.convex_hull(other))
174 } else if self.start <= other.start {
175 OneTwo::Two(self, other)
176 } else {
177 OneTwo::Two(other, self)
178 }
179 }
180
181 #[inline]
187 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
188 match self.intersection(other) {
189 None => ZeroOneTwo::One(self),
190 Some(inter) => {
191 let left = Self::try_new(self.start, inter.start);
192 let right = Self::try_new(inter.end_excl, self.end_excl);
193
194 match (left, right) {
195 (None, None) => ZeroOneTwo::Zero,
196 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
197 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
198 }
199 }
200 }
201 }
202
203 #[inline]
209 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
210 match self.intersection(other) {
211 None => {
212 if self.start <= other.start {
213 ZeroOneTwo::Two(self, other)
214 } else {
215 ZeroOneTwo::Two(other, self)
216 }
217 }
218 Some(inter) => {
219 let hull = self.convex_hull(other);
220 let left = Self::try_new(hull.start, inter.start);
221 let right = Self::try_new(inter.end_excl, hull.end_excl);
222
223 match (left, right) {
224 (None, None) => ZeroOneTwo::Zero,
225 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
226 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
227 }
228 }
229 }
230 }
231 }
232}
233
234pub mod minkowski {
240 use super::*;
241
242 pub mod checked {
243 use super::*;
244
245 impl U8CO {
249 #[inline]
251 pub const fn checked_minkowski_add(self, other: Self) -> Option<Self> {
252 let Some(start) = self.start.checked_add(other.start) else {
253 return None;
254 };
255 let Some(end_excl) = self.end_excl.checked_add(other.end_incl()) else {
256 return None;
257 };
258 Some(Self::new_unchecked(start, end_excl))
259 }
260
261 #[inline]
263 pub const fn checked_minkowski_sub(self, other: Self) -> Option<Self> {
264 let Some(start) = self.start.checked_sub(other.end_incl()) else {
265 return None;
266 };
267 let Some(end_excl) = self.end_excl.checked_sub(other.start) else {
268 return None;
269 };
270 Some(Self::new_unchecked(start, end_excl))
271 }
272
273 #[inline]
275 pub const fn checked_minkowski_mul(self, other: Self) -> Option<Self> {
276 let Some(start) = self.start.checked_mul(other.start) else {
277 return None;
278 };
279 let Some(end_incl) = self.end_incl().checked_mul(other.end_incl()) else {
280 return None;
281 };
282 let Some(end_excl) = end_incl.checked_add(1) else {
283 return None;
284 };
285 Some(Self::new_unchecked(start, end_excl))
286 }
287
288 #[inline]
290 pub const fn checked_minkowski_div(self, other: Self) -> Option<Self> {
291 if other.start == 0 {
292 return None;
293 }
294
295 let Some(start) = self.start.checked_div(other.end_incl()) else {
296 return None;
297 };
298 let Some(end_incl) = self.end_incl().checked_div(other.start) else {
299 return None;
300 };
301 let Some(end_excl) = end_incl.checked_add(1) else {
302 return None;
303 };
304 Some(Self::new_unchecked(start, end_excl))
305 }
306 }
307
308 impl U8CO {
312 #[inline]
314 pub const fn checked_minkowski_add_n(self, n: u8) -> Option<Self> {
315 let Some(start) = self.start.checked_add(n) else {
316 return None;
317 };
318 let Some(end_excl) = self.end_excl.checked_add(n) else {
319 return None;
320 };
321 Some(Self::new_unchecked(start, end_excl))
322 }
323
324 #[inline]
326 pub const fn checked_minkowski_sub_n(self, n: u8) -> Option<Self> {
327 let Some(start) = self.start.checked_sub(n) else {
328 return None;
329 };
330 let Some(end_excl) = self.end_excl.checked_sub(n) else {
331 return None;
332 };
333 Some(Self::new_unchecked(start, end_excl))
334 }
335
336 #[inline]
338 pub const fn checked_minkowski_mul_n(self, n: u8) -> Option<Self> {
339 let Some(start) = self.start.checked_mul(n) else {
340 return None;
341 };
342 let Some(end_incl) = self.end_incl().checked_mul(n) else {
343 return None;
344 };
345 let Some(end_excl) = end_incl.checked_add(1) else {
346 return None;
347 };
348 Some(Self::new_unchecked(start, end_excl))
349 }
350
351 #[inline]
353 pub const fn checked_minkowski_div_n(self, n: u8) -> Option<Self> {
354 if n == 0 {
355 return None;
356 }
357
358 let start = self.start / n;
359 let end_incl = self.end_incl() / n;
360 let Some(end_excl) = end_incl.checked_add(1) else {
361 return None;
362 };
363 Some(Self::new_unchecked(start, end_excl))
364 }
365 }
366 }
367
368 pub mod saturating {
369 use super::*;
370
371 impl U8CO {
375 #[inline]
376 pub const fn saturating_minkowski_add(self, other: Self) -> Option<Self> {
377 let start = self.start.saturating_add(other.start);
378 let end_excl = self.end_excl.saturating_add(other.end_incl());
379 Self::try_new(start, end_excl)
380 }
381
382 #[inline]
383 pub const fn saturating_minkowski_sub(self, other: Self) -> Option<Self> {
384 let start = self.start.saturating_sub(other.end_incl());
385 let end_excl = self.end_excl.saturating_sub(other.start);
386 Self::try_new(start, end_excl)
387 }
388
389 #[inline]
390 pub const fn saturating_minkowski_mul(self, other: Self) -> Option<Self> {
391 let start = self.start.saturating_mul(other.start);
392 let end_incl = self.end_incl().saturating_mul(other.end_incl());
393 let end_excl = end_incl.saturating_add(1);
394 Self::try_new(start, end_excl)
395 }
396
397 #[inline]
398 pub const fn saturating_minkowski_div(self, other: Self) -> Option<Self> {
399 if other.start == 0 {
400 return None;
401 }
402
403 let start = self.start / other.end_incl();
404 let end_incl = self.end_incl() / other.start;
405 let end_excl = end_incl.saturating_add(1);
406 Self::try_new(start, end_excl)
407 }
408 }
409
410 impl U8CO {
414 #[inline]
416 pub const fn saturating_minkowski_add_n(self, n: u8) -> Option<Self> {
417 let start = self.start.saturating_add(n);
418 let end_excl = self.end_excl.saturating_add(n);
419 Self::try_new(start, end_excl)
420 }
421
422 #[inline]
424 pub const fn saturating_minkowski_sub_n(self, n: u8) -> Option<Self> {
425 let start = self.start.saturating_sub(n);
426 let end_excl = self.end_excl.saturating_sub(n);
427 Self::try_new(start, end_excl)
428 }
429
430 #[inline]
432 pub const fn saturating_minkowski_mul_n(self, n: u8) -> Option<Self> {
433 let start = self.start.saturating_mul(n);
434 let end_incl = self.end_incl().saturating_mul(n);
435 let end_excl = end_incl.saturating_add(1);
436 Self::try_new(start, end_excl)
437 }
438
439 #[inline]
441 pub const fn saturating_minkowski_div_n(self, n: u8) -> Option<Self> {
442 if n == 0 {
443 return None;
444 }
445
446 let start = self.start / n;
447 let end_incl = self.end_incl() / n;
448 let end_excl = end_incl.saturating_add(1);
449 Self::try_new(start, end_excl)
450 }
451 }
452 }
453}