1use crate::prelude::*;
4use num_traits::AsPrimitive;
5use std::{
6 array::IntoIter,
7 iter::{FromIterator, Product, Sum},
8 ops::{
9 Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub,
10 SubAssign,
11 },
12};
13
14#[inline]
15pub(crate) fn clamp_size(val: u32) -> i32 {
16 val.clamp(0, i32::MAX as u32 / 2) as i32
17}
18
19#[inline]
20pub(crate) fn clamp_dimensions(width: u32, height: u32) -> (i32, i32) {
21 (clamp_size(width), clamp_size(height))
22}
23
24macro_rules! impl_from_array {
26 ($($Type:ident<T$(, $N:ident)?>),* => [$T:ty; $M:expr]) => {$(
27 impl<T$(, const $N: usize)?> From<[$T; $M]> for $Type<T$(, $N)?> {
28 #[doc = concat!("Converts `[T; M]` to ", stringify!($Type<T$(, $N)?>), ".")]
29 #[inline]
30 fn from(arr: [$T; $M]) -> Self {
31 Self(arr)
32 }
33 }
34 impl<T: Copy$(, const $N: usize)?> From<&[$T; $M]> for $Type<T$(, $N)?> {
35 #[doc = concat!("Converts `&[T; M]` to ", stringify!($Type<T$(, $N)?>), ".")]
36 #[inline]
37 fn from(&arr: &[$T; $M]) -> Self {
38 Self(arr)
39 }
40 }
41 impl<T$(, const $N: usize)?> From<$Type<T$(, $N)?>> for [$T; $M] {
42 #[doc = concat!("Converts ", stringify!($Type<T$(, $N)?>), " to `[T; M]`.")]
43 #[inline]
44 fn from(t: $Type<T$(, $N)?>) -> Self {
45 t.0
46 }
47 }
48 impl<T: Copy$(, const $N: usize)?> From<&$Type<T$(, $N)?>> for [$T; $M] {
49 #[doc = concat!("Converts ", stringify!($Type<T$(, $N)?>), " to `&[T; M]`.")]
50 #[inline]
51 fn from(t: &$Type<T$(, $N)?>) -> Self {
52 t.0
53 }
54 }
55 )*};
56}
57
58impl_from_array!(Ellipse<T>, Rect<T>, Sphere<T> => [T; 4]);
59impl_from_array!(Point<T, N>, Vector<T, N> => [T; N]);
60impl_from_array!(Line<T, N> => [Point<T, N>; 2]);
61impl_from_array!(Tri<T, N> => [Point<T, N>; 3]);
62impl_from_array!(Quad<T, N> => [Point<T, N>; 4]);
63
64macro_rules! impl_as {
66 ($($Type:ident<T$(, $N:ident)?>),*) => {$(
67 impl<T$(, const $N: usize)?> $Type<T$(, $N)?> {
68 #[doc = concat!("Converts ", stringify!($Type<T$(, $N)?>),
69 " to ", stringify!($Type<U$(, $N)?>), ".")]
70 #[inline]
71 pub fn as_<U>(&self) -> $Type<U$(, $N)?>
72 where
73 U: 'static + Copy,
74 T: AsPrimitive<U>
75 {
76 $Type(self.map(AsPrimitive::as_))
77 }
78 }
79 )*};
80 ($($Type:ident<T$(, $N:ident)?>),* from $U:ident) => {$(
81 impl<T$(, const $N: usize)?> $Type<T$(, $N)?> {
82 #[doc = concat!("Converts ", stringify!($Type<T$(, $N)?>),
84 " to ", stringify!($Type<U$(, $N)?>), ".")]
85 #[inline]
86 pub fn as_<U>(&self) -> $Type<U$(, $N)?>
87 where
88 U: 'static + Copy,
89 T: AsPrimitive<U>
90 {
91 $Type(self.map(|p| $U(p.map(AsPrimitive::as_))))
92 }
93 }
94 )*};
95}
96
97impl_as!(Point<T, N>, Vector<T, N>, Ellipse<T>, Rect<T>, Sphere<T>);
98impl_as!(Line<T, N>, Tri<T, N>, Quad<T, N> from Point);
99
100macro_rules! impl_float_conversion {
103 ($($Type:ident<T$(, $N:ident)?>),*) => {$(
104 impl<T: Float$(, const $N: usize)?> $Type<T$(, $N)?> {
105 #[doc = concat!("Returns ", stringify!($Type<T$(, $N)?>),
106 " with the nearest integers to the numbers. Round half-way cases away from 0.0.")]
107 #[inline]
108 pub fn round(&self) -> Self {
109 Self(self.map(num_traits::Float::round))
110 }
111 #[doc = concat!("Returns ", stringify!($Type<T$(, $N)?>),
112 " with the largest integers less than or equal to the numbers.")]
113 #[inline]
114 pub fn floor(&self) -> Self {
115 Self(self.map(num_traits::Float::floor))
116 }
117 #[doc = concat!("Returns ", stringify!($Type<T$(, $N)?>),
118 " with the smallest integers greater than or equal to the numbers.")]
119 #[inline]
120 pub fn ceil(&self) -> Self {
121 Self(self.map(num_traits::Float::ceil))
122 }
123 }
124 )*};
125 ($($Type:ident<T$(, $N:ident)?>),* from $U:ident) => {$(
126 impl<T: Float$(, const $N: usize)?> $Type<T$(, $N)?> {
127 #[doc = concat!("Returns ", stringify!($Type<T$(, $N)?>),
128 " with the nearest integers to the numbers. Round half-way cases away from 0.0.")]
129 #[inline]
130 pub fn round(&self) -> Self {
131 Self(self.map(|p| $U(p.map(num_traits::Float::round))))
132 }
133 #[doc = concat!("Returns ", stringify!($Type<T$(, $N)?>),
134 "with the largest integers less than or equal to the numbers.")]
135 #[inline]
136 pub fn floor(&self) -> Self {
137 Self(self.map(|p| $U(p.map(num_traits::Float::floor))))
138 }
139 #[doc = concat!("Returns ", stringify!($Type<T$(, $N)?>),
140 " with the smallest integers greater than or equal to the numbers.")]
141 #[inline]
142 pub fn ceil(&self) -> Self {
143 Self(self.map(|p| $U(p.map(num_traits::Float::ceil))))
144 }
145 }
146 )*};
147}
148
149impl_float_conversion!(Point<T, N>, Vector<T, N>, Ellipse<T>, Rect<T>, Sphere<T>);
150impl_float_conversion!(Line<T, N>, Tri<T, N>, Quad<T, N> from Point);
151
152macro_rules! impl_wrapper_traits {
154 ($($Type:ident<T$(, $N:ident)?>),* => [$T:ty; $M:expr]) => {
155 $(
156 impl<T$(, const $N: usize)?> Deref for $Type<T$(, $N)?> {
157 type Target = [$T; $M];
158 #[inline]
159 fn deref(&self) -> &Self::Target {
160 &self.0
161 }
162 }
163 impl<T$(, const $N: usize)?> DerefMut for $Type<T$(, $N)?> {
164 #[inline]
165 fn deref_mut(&mut self) -> &mut Self::Target {
166 &mut self.0
167 }
168 }
169
170 impl<T$(, const $N: usize)?> AsRef<[$T; $M]> for $Type<T$(, $N)?> {
171 #[inline]
172 fn as_ref(&self) -> &[$T; $M] {
173 &self.0
174 }
175 }
176 impl<T$(, const $N: usize)?> AsMut<[$T; $M]> for $Type<T$(, $N)?> {
177 #[inline]
178 fn as_mut(&mut self) -> &mut [$T; $M] {
179 &mut self.0
180 }
181 }
182
183 impl<T$(, const $N: usize)?> Index<usize> for $Type<T$(, $N)?> {
184 type Output = $T;
185 #[inline]
186 fn index(&self, idx: usize) -> &Self::Output {
187 &self.0[idx]
188 }
189 }
190 impl<T$(, const $N: usize)?> IndexMut<usize> for $Type<T$(, $N)?> {
191 #[inline]
192 fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
193 &mut self.0[idx]
194 }
195 }
196
197 impl<T$(, const $N: usize)?> IntoIterator for $Type<T$(, $N)?> {
198 type Item = $T;
199 type IntoIter = IntoIter<Self::Item, $M>;
200 #[inline]
201 fn into_iter(self) -> Self::IntoIter {
202 self.0.into_iter()
203 }
204 }
205 impl<'a, T$(, const $N: usize)?> IntoIterator for &'a $Type<T$(, $N)?> {
206 type Item = &'a $T;
207 type IntoIter = std::slice::Iter<'a, $T>;
208 #[inline]
209 fn into_iter(self) -> Self::IntoIter {
210 self.0.iter()
211 }
212 }
213 impl<'a, T$(, const $N: usize)?> IntoIterator for &'a mut $Type<T$(, $N)?> {
214 type Item = &'a mut $T;
215 type IntoIter = std::slice::IterMut<'a, $T>;
216 #[inline]
217 fn into_iter(self) -> Self::IntoIter {
218 self.0.iter_mut()
219 }
220 }
221 impl <T: Default$(, const $N: usize)?> FromIterator<$T> for $Type<T$(, $N)?> {
222 #[inline]
223 fn from_iter<I>(iter: I) -> Self
224 where
225 I: IntoIterator<Item = $T>
226 {
227 let mut iter = iter.into_iter();
228 let arr = [(); $M].map(|_| iter.next().unwrap_or_else(<$T>::default));
229 Self(arr)
230 }
231 }
232 )*
233 };
234}
235
236impl_wrapper_traits!(Ellipse<T>, Rect<T>, Sphere<T> => [T; 4]);
237impl_wrapper_traits!(Point<T, N>, Vector<T, N> => [T; N]);
238impl_wrapper_traits!(Line<T, N> => [Point<T, N>; 2]);
239impl_wrapper_traits!(Tri<T, N> => [Point<T, N>; 3]);
240impl_wrapper_traits!(Quad<T, N> => [Point<T, N>; 4]);
241
242macro_rules! impl_primitive_mul {
245 ($Type:ident => $($target:ty),*) => {
246 $(
247 impl<const N: usize> Mul<$Type<$target, N>> for $target {
248 type Output = $Type<$target, N>;
249 fn mul(self, t: $Type<$target, N>) -> Self::Output {
251 $Type(t.map(|v| self * v))
252 }
253 }
254 )*
255 };
256}
257
258impl_primitive_mul!(Point => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, f32, f64);
259impl_primitive_mul!(Vector => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, f32, f64);
260
261macro_rules! impl_num_assign_op {
262 (@ $OpTrait:ident, $func:ident, $op:tt, $Type:ty) => {
263 impl<T, U, const N: usize> $OpTrait<U> for $Type
264 where
265 T: Num + $OpTrait<U>,
266 U: Num,
267 {
268 fn $func(&mut self, val: U) {
269 for v in self.iter_mut() {
270 *v $op val;
271 }
272 }
273 }
274 };
275 ($OpTrait:ident, $func:ident, $Lhs:ty, $op:tt, $Rhs:ty = $Output:ty) => {
276 impl<T: Num, const N: usize> $OpTrait<$Rhs> for $Lhs {
277 fn $func(&mut self, other: $Rhs) {
278 for (v, o) in self.iter_mut().zip(other) {
279 *v $op o;
280 }
281 }
282 }
283 };
284}
285
286impl_num_assign_op!(AddAssign, add_assign, Point<T, N>, +=, Vector<T, N> = Point<T, N>);
287impl_num_assign_op!(AddAssign, add_assign, Point<T, N>, +=, Point<T, N> = Point<T, N>);
288impl_num_assign_op!(AddAssign, add_assign, Vector<T, N>, +=, Vector<T, N> = Vector<T, N>);
289impl_num_assign_op!(SubAssign, sub_assign, Point<T, N>, -=, Vector<T, N> = Point<T, N>);
290impl_num_assign_op!(SubAssign, sub_assign, Point<T, N>, -=, Point<T, N> = Point<T, N>);
291impl_num_assign_op!(SubAssign, sub_assign, Vector<T, N>, -=, Vector<T, N> = Vector<T, N>);
292
293macro_rules! impl_num_op {
294 (@ $IterTrait:ident, $func:ident, $Bound:ident, $op:tt, $Type:ty) => {
295 impl<T, const N: usize> $IterTrait for $Type
296 where
297 Self: Default + $Bound<Output = Self>,
298 T: Num,
299 {
300 fn $func<I>(iter: I) -> Self
301 where
302 I: Iterator<Item = Self>,
303 {
304 let t = <$Type>::default();
305 iter.fold(t, |a, b| a $op b)
306 }
307 }
308 impl<'a, T, const N: usize> $IterTrait<&'a $Type> for $Type
309 where
310 Self: Default + $Bound<Output = Self>,
311 T: Num,
312 {
313 fn $func<I>(iter: I) -> Self
314 where
315 I: Iterator<Item = &'a Self>,
316 {
317 let t = <$Type>::default();
318 iter.fold(t, |a, b| a $op *b)
319 }
320 }
321 };
322 (@ $OpTrait:ident, $func:ident, $op:tt, $Type:ty) => {
323 impl<T, U, const N: usize> $OpTrait<U> for $Type
324 where
325 T: Num + $OpTrait<U, Output = T>,
326 U: Num,
327 {
328 type Output = Self;
329 fn $func(self, val: U) -> Self::Output {
330 let mut t = <$Type>::default();
331 for (v, s) in t.iter_mut().zip(self) {
332 *v = s $op val;
333 }
334 t
335 }
336 }
337 };
338 ($($Type:ty),*) => {
339 $(
340 impl_num_op!(@ Sum, sum, Add, +, $Type);
341 impl_num_op!(@ Product, product, Mul, *, $Type);
342 impl_num_op!(@ Add, add, +, $Type);
343 impl_num_op!(@ Sub, sub, -, $Type);
344 impl_num_op!(@ Mul, mul, *, $Type);
345 impl_num_op!(@ Div, div, /, $Type);
346 impl_num_assign_op!(@ AddAssign, add_assign, +=, $Type);
347 impl_num_assign_op!(@ SubAssign, sub_assign, -=, $Type);
348 impl_num_assign_op!(@ MulAssign, mul_assign, *=, $Type);
349 impl_num_assign_op!(@ DivAssign, div_assign, /=, $Type);
350 impl<T, const N: usize> Neg for $Type
351 where
352 T: Num + Neg<Output = T>,
353 {
354 type Output = Self;
355 fn neg(self) -> Self::Output {
356 let mut t = <$Type>::default();
357 for (v, s) in t.iter_mut().zip(self) {
358 *v = s.neg();
359 }
360 t
361 }
362 }
363
364 )*
365 };
366 ($OpTrait:ident, $func:ident, $Lhs:ty, $op:tt, $Rhs:ty = $Output:ty) => {
367 impl<T, const N: usize> $OpTrait<$Rhs> for $Lhs
368 where
369 T: Num + $OpTrait,
370 {
371 type Output = $Output;
372 fn $func(self, other: $Rhs) -> Self::Output {
373 let mut t = <$Output>::default();
374 for ((v, s), o) in t.iter_mut().zip(self).zip(other) {
375 *v = s $op o;
376 }
377 t
378 }
379 }
380 };
381}
382
383impl_num_op!(Point<T, N>, Vector<T, N>);
384impl_num_op!(Add, add, Point<T, N>, +, Point<T, N> = Vector<T, N>);
385impl_num_op!(Add, add, Point<T, N>, +, Vector<T, N> = Point<T, N>);
386impl_num_op!(Add, add, Vector<T, N>, +, Point<T, N> = Point<T, N>);
387impl_num_op!(Add, add, Vector<T, N>, +, Vector<T, N> = Vector<T, N>);
388impl_num_op!(Sub, sub, Point<T, N>, -, Point<T, N> = Vector<T, N>);
389impl_num_op!(Sub, sub, Point<T, N>, -, Vector<T, N> = Point<T, N>);
390impl_num_op!(Sub, sub, Vector<T, N>, -, Point<T, N> = Point<T, N>);
391impl_num_op!(Sub, sub, Vector<T, N>, -, Vector<T, N> = Vector<T, N>);
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396
397 #[test]
398 fn iter_ops() {
399 let p = point!(1, 2, 3);
400 assert_eq!(p.deref(), &[1, 2, 3]);
401 let mut p = point!(1, 2, 3);
402 assert_eq!(p.deref_mut(), &mut [1, 2, 3]);
403
404 let p = point!(1, 2, 3);
405 assert_eq!(p[0], 1);
406 assert_eq!(p[1], 2);
407 assert_eq!(p[2], 3);
408 assert_eq!(p.get(3), None);
409
410 let p = point!(1, 2, 3);
411 for (i, v) in p.into_iter().enumerate() {
412 assert_eq!(v, p[i]);
413 }
414 let i = IntoIterator::into_iter([1, 2, 3]);
415 let p = Point::from_iter(i);
416 assert_eq!(p, point!(1, 2, 3));
417 }
418
419 #[test]
420 fn from_array() {
421 macro_rules! test {
422 ($Type:ident, $N:expr; $($T:ty),* => $arr:expr) => {$(
423 let t: $Type<$T, $N> = $arr.into();
424 assert_eq!(t.deref(), &$arr);
425 let v: [$T; $N] = <$Type<$T, $N>>::new($arr).into();
426 assert_eq!(v, $arr);
427 )*};
428 }
429 test!(Point, 1; i8, u8, i16, u16, i32, u32, i64, u64, i128, u128 => [1]);
430 test!(Point, 2; i8, u8, i16, u16, i32, u32, i64, u64, i128, u128 => [1, 2]);
431 test!(Point, 3; i8, u8, i16, u16, i32, u32, i64, u64, i128, u128 => [1, 2, 3]);
432 test!(Vector, 1; i8, u8, i16, u16, i32, u32, i64, u64, i128, u128 => [1]);
433 test!(Vector, 2; i8, u8, i16, u16, i32, u32, i64, u64, i128, u128 => [1, 2]);
434 test!(Vector, 3; i8, u8, i16, u16, i32, u32, i64, u64, i128, u128 => [1, 2, 3]);
435 }
436}