Skip to main content

int_interval/
u8.rs

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 union_tests;
15
16#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
17pub struct U8CO {
18    start: u8,
19    end_excl: u8,
20}
21
22// ------------------------------------------------------------
23// low-level api: construction / accessors / predicates
24// ------------------------------------------------------------
25
26impl U8CO {
27    #[inline]
28    pub const fn try_new(start: u8, end_excl: u8) -> Option<Self> {
29        if start < end_excl {
30            Some(Self { start, end_excl })
31        } else {
32            None
33        }
34    }
35
36    #[inline]
37    pub const fn new_unchecked(start: u8, end_excl: u8) -> Self {
38        debug_assert!(start < end_excl);
39        Self { start, end_excl }
40    }
41
42    #[inline]
43    pub const fn start(self) -> u8 {
44        self.start
45    }
46
47    #[inline]
48    pub const fn end_excl(self) -> u8 {
49        self.end_excl
50    }
51
52    #[inline]
53    pub const fn len(self) -> u8 {
54        self.end_excl - self.start
55    }
56
57    #[inline]
58    pub const fn contains(self, x: u8) -> bool {
59        self.start <= x && x < self.end_excl
60    }
61
62    #[inline]
63    pub const fn iter(self) -> core::ops::Range<u8> {
64        self.start..self.end_excl
65    }
66
67    #[inline]
68    pub const fn intersects(self, other: Self) -> bool {
69        !(self.end_excl <= other.start || other.end_excl <= self.start)
70    }
71
72    #[inline]
73    pub const fn is_adjacent(self, other: Self) -> bool {
74        self.end_excl == other.start || other.end_excl == self.start
75    }
76
77    #[inline]
78    pub const fn is_contiguous_with(self, other: Self) -> bool {
79        self.intersects(other) || self.is_adjacent(other)
80    }
81}
82
83// ------------------------------------------------------------
84// high-level api: interval algebra
85// ------------------------------------------------------------
86
87impl U8CO {
88    #[inline]
89    pub const fn intersection(self, other: Self) -> Option<Self> {
90        let start = if self.start >= other.start {
91            self.start
92        } else {
93            other.start
94        };
95
96        let end_excl = if self.end_excl <= other.end_excl {
97            self.end_excl
98        } else {
99            other.end_excl
100        };
101
102        Self::try_new(start, end_excl)
103    }
104}
105
106impl U8CO {
107    #[inline]
108    pub const fn convex_hull(self, other: Self) -> Self {
109        let start = if self.start <= other.start {
110            self.start
111        } else {
112            other.start
113        };
114
115        let end_excl = if self.end_excl >= other.end_excl {
116            self.end_excl
117        } else {
118            other.end_excl
119        };
120
121        Self { start, end_excl }
122    }
123}
124
125impl U8CO {
126    #[inline]
127    pub const fn between(self, other: Self) -> Option<Self> {
128        let (left, right) = if self.start <= other.start {
129            (self, other)
130        } else {
131            (other, self)
132        };
133
134        Self::try_new(left.end_excl, right.start)
135    }
136}
137
138impl U8CO {
139    #[inline]
140    pub const fn union(self, other: Self) -> OneTwo<Self> {
141        if self.is_contiguous_with(other) {
142            OneTwo::One(self.convex_hull(other))
143        } else if self.start <= other.start {
144            OneTwo::Two(self, other)
145        } else {
146            OneTwo::Two(other, self)
147        }
148    }
149}
150
151impl U8CO {
152    #[inline]
153    pub const fn difference(self, other: Self) -> ZeroOneTwo<Self> {
154        match self.intersection(other) {
155            None => ZeroOneTwo::One(self),
156            Some(inter) => {
157                let left = Self::try_new(self.start, inter.start);
158                let right = Self::try_new(inter.end_excl, self.end_excl);
159
160                match (left, right) {
161                    (None, None) => ZeroOneTwo::Zero,
162                    (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
163                    (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
164                }
165            }
166        }
167    }
168}
169
170impl U8CO {
171    #[inline]
172    pub const fn symmetric_difference(self, other: Self) -> ZeroOneTwo<Self> {
173        match self.intersection(other) {
174            None => {
175                if self.start <= other.start {
176                    ZeroOneTwo::Two(self, other)
177                } else {
178                    ZeroOneTwo::Two(other, self)
179                }
180            }
181            Some(inter) => {
182                let hull = self.convex_hull(other);
183                let left = Self::try_new(hull.start, inter.start);
184                let right = Self::try_new(inter.end_excl, hull.end_excl);
185
186                match (left, right) {
187                    (None, None) => ZeroOneTwo::Zero,
188                    (Some(x), None) | (None, Some(x)) => ZeroOneTwo::One(x),
189                    (Some(x), Some(y)) => ZeroOneTwo::Two(x, y),
190                }
191            }
192        }
193    }
194}