devela/geom/metric/
extent.rs1use crate::{is, whilst};
15
16#[doc = crate::_tags!(geom)]
17#[doc = crate::_doc_meta!{location("geom/metric")}]
19#[must_use]
26#[repr(transparent)]
27#[doc(alias = "Size")]
28pub struct Extent<T, const D: usize> {
29 pub dim: [T; D],
31}
32
33#[doc = crate::_tags!(geom)]
34#[doc = crate::_doc_meta!{location("geom/metric")}]
36#[doc(alias = "Size")]
37pub type Extent1<T> = Extent<T, 1>;
38
39#[doc = crate::_tags!(geom)]
40#[doc = crate::_doc_meta!{location("geom/metric")}]
42#[doc(alias = "Size")]
43pub type Extent2<T> = Extent<T, 2>;
44
45#[doc = crate::_tags!(geom)]
46#[doc = crate::_doc_meta!{location("geom/metric")}]
48#[doc(alias = "Size")]
49pub type Extent3<T> = Extent<T, 3>;
50
51crate::_geom_dim_impl_common![common_methods: Extent];
52crate::_geom_dim_impl_common![common_traits: Extent];
53
54macro_rules! impl_extent {
56 () => {
57 impl_extent![sint i8, i16, i32, i64, i128, isize];
58 impl_extent![uint u8, u16, u32, u64, u128, usize];
59 impl_extent![float f32, f64];
60 };
61 (int $($t:ty),+) => { $( impl_extent![@int $t]; )+ };
65 (@int $t:ty) => {
66 impl<const D: usize> Extent<$t, D> {
67 #[must_use]
68 pub const fn measure(self) -> $t {
72 let mut measure = 1;
73 whilst!(i in 0..D; measure *= self.dim[i]);
74 measure
75 }
76 #[must_use]
77 pub const fn boundary(self) -> $t {
81 let mut boundary = 0;
82 whilst!(i in 0..D; {
83 let mut face_measure = 1;
84 whilst!(j in 0..D; is![i != j, face_measure *= self.dim[j]]);
85 boundary += face_measure;
86 });
87 2 * boundary }
89 }
90
91 impl Extent2<$t> {
93 #[must_use]
94 pub const fn area(self) -> $t { self.dim[0] * self.dim[1] }
96 #[must_use]
97 pub const fn perimeter(self) -> $t { 2 * (self.dim[0] + self.dim[1]) }
99 }
100 impl Extent3<$t> {
101 #[must_use]
102 pub const fn volume(self) -> $t {
104 self.dim[0] * self.dim[1] * self.dim[2]
105 }
106 #[must_use]
107 pub const fn surface_area(self) -> $t {
109 2 * (self.dim[0] * self.dim[1]
110 + self.dim[1] * self.dim[2]
111 + self.dim[2] * self.dim[0])
112 }
113 }
114 };
115
116 (sint $($t:ty),+) => { $( impl_extent![@sint $t]; )+ };
117 (@sint $t:ty ) => {
118 impl_extent![int $t];
119 };
120 (uint $($t:ty),+) => { $( impl_extent![@uint $t]; )+ };
121 (@uint $t:ty ) => {
122 impl_extent![int $t];
123 };
124
125 (float $($f:ty),+) => { $( impl_extent![@float $f]; )+ };
127 (@float $f:ty) => {
128 impl<const D: usize> Extent<$f, D> {
129 #[must_use]
130 pub const fn measure(self) -> $f {
134 let mut measure = 1.0;
135 whilst!(i in 0..D; measure *= self.dim[i]);
136 measure
137 }
138 #[must_use]
139 pub const fn boundary(self) -> $f {
143 let mut boundary = 0.0;
144 whilst!(i in 0..D; {
145 let mut face_measure = 1.0;
146 whilst!(j in 0..D; is![i != j, face_measure *= self.dim[j]]);
147 boundary += face_measure;
148 });
149 2.0 * boundary }
151 }
152
153 impl Extent2<$f> {
154 #[must_use]
155 pub const fn area(self) -> $f { self.dim[0] * self.dim[1] }
157 #[must_use]
158 pub const fn perimeter(self) -> $f { 2.0 * (self.dim[0] + self.dim[1]) }
160 }
161 impl Extent3<$f> {
162 #[must_use]
163 pub const fn volume(self) -> $f {
165 self.dim[0] * self.dim[1] * self.dim[2]
166 }
167 #[must_use]
168 pub const fn surface_area(self) -> $f {
170 2.0 * (self.dim[0] * self.dim[1]
171 + self.dim[1] * self.dim[2]
172 + self.dim[2] * self.dim[0])
173 }
174 }
175 };
176}
177impl_extent![];
178
179#[rustfmt::skip]
180impl<T: Copy> Extent1<T> {
182 #[must_use]
183 pub const fn length(self) -> T { self.dim[0] }
185 pub const fn l(self) -> T { self.dim[0] }
187}
188
189#[rustfmt::skip]
190impl<T: Copy> Extent2<T> {
192 #[must_use]
193 pub const fn width(self) -> T { self.dim[0] }
195 #[must_use]
196 pub const fn w(self) -> T { self.dim[0] }
198 #[must_use]
199 pub const fn height(self) -> T { self.dim[1] }
201 #[must_use]
202 pub const fn h(self) -> T { self.dim[1] }
204
205 #[must_use]
206 pub const fn length(self) -> T { self.dim[0] }
208 #[must_use]
209 pub const fn l(self) -> T { self.dim[0] }
211 #[must_use]
212 pub const fn breadth(self) -> T { self.dim[1] }
214 #[must_use]
215 pub const fn b(self) -> T { self.dim[1] }
217}
218
219#[rustfmt::skip]
220impl<T: Copy> Extent3<T> {
222 #[must_use]
223 pub const fn width(self) -> T { self.dim[0] }
225 #[must_use]
226 pub const fn w(self) -> T { self.dim[0] }
228 #[must_use]
229 pub const fn height(self) -> T { self.dim[1] }
231 #[must_use]
232 pub const fn h(self) -> T { self.dim[1] }
234 #[must_use]
235 pub const fn depth(self) -> T { self.dim[2] }
237 #[must_use]
238 pub const fn d(self) -> T { self.dim[2] }
240}
241
242#[cfg(test)]
243mod tests {
244 use crate::{Extent2, ext};
245
246 #[test]
247 fn test_runtime_conversion_methods() {
248 let a = ext!(300_u16, 40_u16);
249
250 let _b: Extent2<u32> = a.map_into();
251 let _c: Result<Extent2<u8>, _> = a.try_map_into();
252 let _d = a.map(|x| x as f32 * 0.5);
253 let _e: Result<Extent2<u8>, _> = a.try_map(u8::try_from);
254 }
255}