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