1use crate::geometry::Face;
2
3use super::{Region, Side};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
7pub struct Split<const N: usize>(usize);
8
9impl<const N: usize> Split<N> {
10 pub const COUNT: usize = 2usize.pow(N as u32);
12
13 pub const fn enumerate() -> SplitIter<N> {
15 SplitIter { cursor: 0 }
16 }
17
18 pub const fn empty() -> Self {
20 Self(0)
21 }
22
23 pub const fn full() -> Self {
25 Self(usize::MAX)
26 }
27
28 pub fn from_linear(linear: usize) -> Self {
30 Self(linear)
31 }
32
33 pub fn to_linear(self) -> usize {
35 self.0.min(Self::COUNT - 1)
36 }
37
38 pub fn unpack(self) -> [bool; N] {
40 let mut result = [false; N];
41
42 for axis in 0..N {
43 result[axis] = self.is_set(axis);
44 }
45
46 result
47 }
48
49 pub fn pack(bits: [bool; N]) -> Self {
51 let mut result = Self::empty();
52
53 for (i, bit) in bits.into_iter().enumerate() {
54 result.set_to(i, bit);
55 }
56
57 result
58 }
59
60 pub fn set(&mut self, axis: usize) {
62 self.0 |= 1 << axis
63 }
64
65 pub fn clear(&mut self, axis: usize) {
67 self.0 &= !(1 << axis)
68 }
69
70 pub fn set_to(&mut self, axis: usize, value: bool) {
72 self.0 &= !(1 << axis);
73 self.0 |= (value as usize) << axis;
74 }
75
76 pub fn toggle(&mut self, axis: usize) {
78 self.0 ^= 1 << axis
79 }
80
81 pub fn toggled(mut self, axis: usize) -> Self {
83 self.0 ^= 1 << axis;
84 self
85 }
86
87 pub fn is_set(self, axis: usize) -> bool {
89 (self.0 & (1 << axis)) != 0
90 }
91
92 pub fn is_inner_face(self, face: Face<N>) -> bool {
93 self.is_set(face.axis) != face.side
94 }
95
96 pub fn is_outer_face(self, face: Face<N>) -> bool {
97 self.is_set(face.axis) == face.side
98 }
99
100 pub fn inner_faces(self) -> impl Iterator<Item = Face<N>> {
101 Face::<N>::iterate().filter(move |&face| self.is_inner_face(face))
102 }
103
104 pub fn outer_faces(self) -> impl Iterator<Item = Face<N>> {
105 Face::<N>::iterate().filter(move |&face| self.is_outer_face(face))
106 }
107
108 pub fn as_inner_face(mut self, face: Face<N>) -> Self {
109 self.set_to(face.axis, !face.side);
110 self
111 }
112
113 pub fn as_outer_face(mut self, face: Face<N>) -> Self {
114 self.set_to(face.axis, face.side);
115 self
116 }
117
118 pub fn is_inner_region(self, region: Region<N>) -> bool {
119 for axis in 0..N {
120 match (region.side(axis), self.is_set(axis)) {
121 (Side::Left, false) => return false,
122 (Side::Right, true) => return false,
123 _ => {}
124 }
125 }
126
127 true
128 }
129
130 pub fn is_outer_region(self, region: Region<N>) -> bool {
131 !self.is_inner_region(region)
132 }
133
134 pub fn as_inner_region(mut self, region: Region<N>) -> Self {
135 for axis in 0..N {
136 match region.side(axis) {
137 Side::Left => self.set_to(axis, true),
138 Side::Right => self.set_to(axis, false),
139 _ => {}
140 }
141 }
142
143 self
144 }
145
146 pub fn as_outer_region(mut self, region: Region<N>) -> Self {
147 for axis in 0..N {
148 match region.side(axis) {
149 Side::Left => self.set_to(axis, false),
150 Side::Right => self.set_to(axis, true),
151 _ => {}
152 }
153 }
154
155 self
156 }
157}
158
159impl<const N: usize> datasize::DataSize for Split<N> {
160 const IS_DYNAMIC: bool = false;
161 const STATIC_HEAP_SIZE: usize = 0;
162
163 fn estimate_heap_size(&self) -> usize {
164 0
165 }
166}
167
168pub struct SplitIter<const N: usize> {
170 cursor: usize,
171}
172
173impl<const N: usize> Iterator for SplitIter<N> {
174 type Item = Split<N>;
175
176 fn next(&mut self) -> Option<Self::Item> {
177 if self.cursor >= Split::<N>::COUNT {
178 return None;
179 }
180
181 let result = self.cursor;
182 self.cursor += 1;
183 Some(Split::from_linear(result))
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn masks() {
193 let mut splits = Split::<2>::enumerate();
194 assert_eq!(splits.next(), Some(Split::pack([false, false])));
195 assert_eq!(splits.next(), Some(Split::pack([true, false])));
196 assert_eq!(splits.next(), Some(Split::pack([false, true])));
197 assert_eq!(splits.next(), Some(Split::pack([true, true])));
198 assert_eq!(splits.next(), None);
199
200 let mut faces = Split::<2>::pack([false, true]).outer_faces();
201 assert_eq!(faces.next(), Some(Face::<2>::negative(0)));
202 assert_eq!(faces.next(), Some(Face::<2>::positive(1)));
203 assert_eq!(faces.next(), None);
204 }
205}