1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
5pub struct Dim {
6 pub x: u32,
7 pub y: u32,
8 pub z: u32,
9}
10
11impl Dim {
12 pub const ZERO: Self = Self { x: 0, y: 0, z: 0 };
13
14 #[must_use]
15 #[inline]
16 pub fn new(x: u32, y: u32, z: u32) -> Self {
17 Self { x, y, z }
18 }
19
20 #[must_use]
21 #[inline]
22 pub fn size(&self) -> u64 {
23 u64::from(self.x) * u64::from(self.y) * u64::from(self.z)
24 }
25
26 #[must_use]
27 #[inline]
28 fn as_tuple(&self) -> (&u32, &u32, &u32) {
29 (&self.x, &self.y, &self.z)
30 }
31}
32
33impl std::fmt::Display for Dim {
34 #[inline]
35 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36 write!(f, "({},{},{})", self.x, self.y, self.z)
37 }
38}
39
40impl From<u32> for Dim {
41 #[inline]
42 fn from(dim: u32) -> Self {
43 Self { x: dim, y: 1, z: 1 }
44 }
45}
46
47impl From<(u32, u32)> for Dim {
48 #[inline]
49 fn from(dim: (u32, u32)) -> Self {
50 let (x, y) = dim;
51 Self { x, y, z: 1 }
52 }
53}
54
55impl From<(u32, u32, u32)> for Dim {
56 #[inline]
57 fn from(dim: (u32, u32, u32)) -> Self {
58 let (x, y, z) = dim;
59 Self { x, y, z }
60 }
61}
62
63impl From<Point> for Dim {
64 #[inline]
65 fn from(p: Point) -> Self {
66 let Point { x, y, z, .. } = p;
67 Self { x, y, z }
68 }
69}
70
71impl PartialEq<Point> for Dim {
72 fn eq(&self, other: &Point) -> bool {
73 self.x == other.x && self.y == other.y && self.z == other.z
74 }
75}
76
77impl Ord for Dim {
78 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
79 self.as_tuple().cmp(&other.as_tuple())
80 }
81}
82
83impl PartialOrd for Dim {
84 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
85 Some(self.cmp(other))
86 }
87}
88
89impl Ord for Point {
90 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
91 self.as_tuple().cmp(&other.as_tuple())
92 }
93}
94
95impl PartialOrd for Point {
96 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
97 Some(self.cmp(other))
98 }
99}
100
101#[derive(Debug, Clone)]
103pub struct Iter {
104 bounds: Dim,
105 current: u64,
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
110pub struct Point {
111 pub x: u32,
112 pub y: u32,
113 pub z: u32,
114 pub bounds: Dim,
115}
116
117impl std::fmt::Display for Point {
118 #[inline]
119 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
120 write!(f, "({},{},{})", self.x, self.y, self.z)
121 }
122}
123
124impl Point {
125 #[must_use]
127 #[inline]
128 pub fn id(&self) -> u64 {
129 let yz = u64::from(self.bounds.y) * u64::from(self.bounds.z);
130 let z = u64::from(self.bounds.z);
131 u64::from(self.x) * yz + u64::from(self.y) * z + u64::from(self.z)
132 }
133
134 #[must_use]
135 #[inline]
136 pub fn size(&self) -> u64 {
137 self.bounds.size()
138 }
139
140 #[must_use]
141 #[inline]
142 pub fn as_tuple(&self) -> (&u32, &u32, &u32) {
143 (&self.x, &self.y, &self.z)
144 }
145
146 #[must_use]
147 #[inline]
148 pub fn into_tuple(self) -> (u32, u32, u32) {
149 self.into()
150 }
151}
152
153impl From<Point> for (u32, u32, u32) {
154 fn from(dim: Point) -> Self {
155 (dim.x, dim.y, dim.z)
156 }
157}
158
159impl Iter {
160 #[must_use]
161 #[inline]
162 pub fn size(&self) -> u64 {
163 self.bounds.size()
164 }
165}
166
167impl Iterator for Iter {
168 type Item = Point;
169
170 #[allow(clippy::cast_possible_truncation)]
171 #[allow(clippy::cast_lossless)]
172 fn next(&mut self) -> Option<Self::Item> {
173 let Self { current, bounds } = *self;
174 if current >= bounds.size() {
175 return None;
176 }
177 let x = current / (bounds.y * bounds.z) as u64;
178 let yz = current % (bounds.y * bounds.z) as u64;
179 let y = yz / bounds.z as u64;
180 let z = yz % bounds.z as u64;
181 self.current += 1;
182 Some(Point {
183 x: x as u32,
184 y: y as u32,
185 z: z as u32,
186 bounds,
187 })
188 }
189}
190
191impl IntoIterator for Dim {
192 type Item = Point;
193 type IntoIter = Iter;
194
195 fn into_iter(self) -> Self::IntoIter {
196 Iter {
197 bounds: self,
198 current: 0,
199 }
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::{Dim, Point};
206 use pretty_assertions as diff;
207
208 #[test]
209 fn test_zero_constant() {
210 let dim: Dim = Dim::ZERO;
211 diff::assert_eq!(dim.size(), 0);
212 }
213
214 mod sort {
215 use super::{diff, Dim, Point};
216
217 #[test]
218 fn test_sort_3_1_1() {
219 let dim: Dim = Dim::from((3, 1, 1));
220 diff::assert_eq!(
221 dim.into_iter().map(Point::into_tuple).collect::<Vec<_>>(),
222 vec![(0, 0, 0), (1, 0, 0), (2, 0, 0)]
223 );
224 }
225
226 #[test]
227 fn test_sort_2_2_2() {
228 let dim: Dim = Dim::from((2, 2, 2));
229 diff::assert_eq!(
230 dim.into_iter().map(Point::into_tuple).collect::<Vec<_>>(),
231 vec![
232 (0, 0, 0),
233 (0, 0, 1),
234 (0, 1, 0),
235 (0, 1, 1),
236 (1, 0, 0),
237 (1, 0, 1),
238 (1, 1, 0),
239 (1, 1, 1)
240 ]
241 );
242 }
243 }
244
245 mod iter {
246 use super::{diff, Dim, Point};
247
248 #[test]
249 fn test_iter_3_1_1() {
250 let dim: Dim = Dim::from((3, 1, 1));
251 diff::assert_eq!(
252 dim.into_iter().map(Point::into_tuple).collect::<Vec<_>>(),
253 vec![(0, 0, 0), (1, 0, 0), (2, 0, 0)]
254 );
255 }
256
257 #[test]
258 fn test_iter_3_3_1() {
259 let dim: Dim = Dim::from((3, 3, 1));
260 let dim_iter = dim.into_iter();
261 assert_eq!(dim_iter.size(), 9);
262 diff::assert_eq!(
263 dim_iter
264 .map(|d| ((d.x, d.y, d.z), d.id()))
265 .collect::<Vec<_>>(),
266 vec![
267 ((0, 0, 0), 0),
268 ((0, 1, 0), 1),
269 ((0, 2, 0), 2),
270 ((1, 0, 0), 3),
271 ((1, 1, 0), 4),
272 ((1, 2, 0), 5),
273 ((2, 0, 0), 6),
274 ((2, 1, 0), 7),
275 ((2, 2, 0), 8)
276 ]
277 );
278 }
279
280 #[test]
281 fn test_iter_1_3_1() {
282 let dim: Dim = Dim::from((1, 3, 1));
283 diff::assert_eq!(
284 dim.into_iter().map(Point::into_tuple).collect::<Vec<_>>(),
285 vec![(0, 0, 0), (0, 1, 0), (0, 2, 0),]
286 );
287 }
288
289 #[test]
290 fn test_iter_3_1_3() {
291 let dim: Dim = Dim::from((3, 1, 3));
292 diff::assert_eq!(
293 dim.into_iter().map(Point::into_tuple).collect::<Vec<_>>(),
294 vec![
295 (0, 0, 0),
296 (0, 0, 1),
297 (0, 0, 2),
298 (1, 0, 0),
299 (1, 0, 1),
300 (1, 0, 2),
301 (2, 0, 0),
302 (2, 0, 1),
303 (2, 0, 2),
304 ]
305 );
306 }
307 }
308}