nvbit_model/
dim.rs

1use serde::{Deserialize, Serialize};
2
3/// 3-dimensional coordinates.
4#[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/// Iterates over 3-dimensional coordinates.
102#[derive(Debug, Clone)]
103pub struct Iter {
104    bounds: Dim,
105    current: u64,
106}
107
108/// 3-dimensional coordinates within 3 dimensional bounds.
109#[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    /// Returns the unique id in the block
126    #[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}