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 symmetric_difference_tests;
13#[cfg(test)]
14mod minkowski_tests;
15#[cfg(test)]
16mod union_tests;
17
18#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
19pub struct U8CO {
20 start: u8,
21 end_excl: u8,
22}
23
24mod construction_accessors_predicates {
29
30 use super::*;
31
32 impl U8CO {
33 #[inline]
34 pub const fn try_new(start: u8, end_excl: u8) -> Option<Self> {
35 if start < end_excl {
36 Some(Self { start, end_excl })
37 } else {
38 None
39 }
40 }
41
42 #[inline]
43 pub(super) const fn new_unchecked(start: u8, end_excl: u8) -> Self {
44 debug_assert!(start < end_excl);
45 Self { start, end_excl }
46 }
47
48 #[inline]
49 pub const fn start(self) -> u8 {
50 self.start
51 }
52
53 #[inline]
54 pub const fn end_excl(self) -> u8 {
55 self.end_excl
56 }
57
58 #[inline]
59 pub const fn end_incl(self) -> u8 {
60 self.end_excl - 1
62 }
63
64 #[inline]
65 pub const fn len(self) -> u8 {
66 self.end_excl - self.start
67 }
68
69 #[inline]
70 pub const fn contains(self, x: u8) -> bool {
71 self.start <= x && x < self.end_excl
72 }
73
74 #[inline]
75 pub const fn iter(self) -> core::ops::Range<u8> {
76 self.start..self.end_excl
77 }
78
79 #[inline]
80 pub const fn intersects(self, other: Self) -> bool {
81 !(self.end_excl <= other.start || other.end_excl <= self.start)
82 }
83
84 #[inline]
85 pub const fn is_adjacent(self, other: Self) -> bool {
86 self.end_excl == other.start || other.end_excl == self.start
87 }
88
89 #[inline]
90 pub const fn is_contiguous_with(self, other: Self) -> bool {
91 self.intersects(other) || self.is_adjacent(other)
92 }
93 }
94}
95
96mod interval_algebra {
101
102 use super::*;
103
104 impl U8CO {
105 #[inline]
109 pub const fn intersection(self, other: Self) -> Option<Self> {
110 let start = if self.start >= other.start {
111 self.start
112 } else {
113 other.start
114 };
115
116 let end_excl = if self.end_excl <= other.end_excl {
117 self.end_excl
118 } else {
119 other.end_excl
120 };
121
122 Self::try_new(start, end_excl)
123 }
124
125 #[inline]
129 pub const fn convex_hull(self, other: Self) -> Self {
130 let start = if self.start <= other.start {
131 self.start
132 } else {
133 other.start
134 };
135
136 let end_excl = if self.end_excl >= other.end_excl {
137 self.end_excl
138 } else {
139 other.end_excl
140 };
141
142 Self { start, end_excl }
143 }
144
145 #[inline]
149 pub const fn between(self, other: Self) -> Option<Self> {
150 let (left, right) = if self.start <= other.start {
151 (self, other)
152 } else {
153 (other, self)
154 };
155
156 Self::try_new(left.end_excl, right.start)
157 }
158
159 #[inline]
164 pub const fn union(self, other: Self) -> OneTwo<Self> {
165 if self.is_contiguous_with(other) {
166 OneTwo::One(self.convex_hull(other))
167 } else if self.start <= other.start {
168 OneTwo::Two(self, other)
169 } else {
170 OneTwo::Two(other, self)
171 }
172 }
173
174 #[inline]
180 pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
181 match self.intersection(other) {
182 None => ZeroOneTwo::One(self),
183 Some(inter) => {
184 let left = Self::try_new(self.start, inter.start);
185 let right = Self::try_new(inter.end_excl, self.end_excl);
186
187 match (left, right) {
188 (None, None) => ZeroOneTwo::Zero,
189 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
190 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
191 }
192 }
193 }
194 }
195
196 #[inline]
202 pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
203 match self.intersection(other) {
204 None => {
205 if self.start <= other.start {
206 ZeroOneTwo::Two(self, other)
207 } else {
208 ZeroOneTwo::Two(other, self)
209 }
210 }
211 Some(inter) => {
212 let hull = self.convex_hull(other);
213 let left = Self::try_new(hull.start, inter.start);
214 let right = Self::try_new(inter.end_excl, hull.end_excl);
215
216 match (left, right) {
217 (None, None) => ZeroOneTwo::Zero,
218 (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
219 (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
220 }
221 }
222 }
223 }
224 }
225}
226
227pub mod minkowski {
233 use super::U8CO;
234
235 impl U8CO {
239 #[inline]
241 pub const fn minkowski_add(self, other: Self) -> Option<Self> {
242 match self.start.checked_add(other.start) {
243 Some(start) => match self.end_incl().checked_add(other.end_incl()) {
244 Some(end_incl) => match end_incl.checked_add(1) {
245 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
246 None => None,
247 },
248 None => None,
249 },
250 None => None,
251 }
252 }
253
254 #[inline]
256 pub const fn minkowski_sub(self, other: Self) -> Option<Self> {
257 match self.start.checked_sub(other.end_incl()) {
258 Some(start) => match self.end_incl().checked_sub(other.start) {
259 Some(end_incl) => match end_incl.checked_add(1) {
260 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
261 None => None,
262 },
263 None => None,
264 },
265 None => None,
266 }
267 }
268
269 #[inline]
271 pub const fn minkowski_mul(self, other: Self) -> Option<Self> {
272 match self.start.checked_mul(other.start) {
273 Some(start) => match self.end_incl().checked_mul(other.end_incl()) {
274 Some(end_incl) => match end_incl.checked_add(1) {
275 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
276 None => None,
277 },
278 None => None,
279 },
280 None => None,
281 }
282 }
283
284 #[inline]
286 pub const fn minkowski_div(self, other: Self) -> Option<Self> {
287 if other.start == 0 {
288 return None; }
290 match self.start.checked_div(other.end_incl()) {
291 Some(start) => match self.end_incl().checked_div(other.start) {
292 Some(end_incl) => match end_incl.checked_add(1) {
293 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
294 None => None,
295 },
296 None => None,
297 },
298 None => None,
299 }
300 }
301 }
302
303 impl U8CO {
307 #[inline]
309 pub const fn minkowski_add_n(self, n: u8) -> Option<Self> {
310 match self.start.checked_add(n) {
311 Some(start) => match self.end_excl.checked_add(n) {
312 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
313 None => None,
314 },
315 None => None,
316 }
317 }
318
319 #[inline]
321 pub const fn minkowski_sub_n(self, n: u8) -> Option<Self> {
322 match self.start.checked_sub(n) {
323 Some(start) => match self.end_excl.checked_sub(n) {
324 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
325 None => None,
326 },
327 None => None,
328 }
329 }
330
331 #[inline]
333 pub const fn minkowski_mul_n(self, n: u8) -> Option<Self> {
334 match self.start.checked_mul(n) {
335 Some(start) => match self.end_incl().checked_mul(n) {
336 Some(end_incl) => match end_incl.checked_add(1) {
337 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
338 None => None,
339 },
340 None => None,
341 },
342 None => None,
343 }
344 }
345
346 #[inline]
348 pub const fn minkowski_div_n(self, n: u8) -> Option<Self> {
349 if n == 0 {
350 return None; }
352 let start = self.start / n;
353 let end_incl = self.end_incl() / n;
354 match end_incl.checked_add(1) {
355 Some(end_excl) => Some(Self::new_unchecked(start, end_excl)),
356 None => None,
357 }
358 }
359 }
360}