retrofire_core/math/
vec.rs

1//! Real and projective vectors.
2//!
3//! TODO
4
5use core::array;
6use core::fmt::{Debug, Formatter};
7use core::iter::Sum;
8use core::marker::PhantomData;
9use core::ops::{Add, Div, Index, IndexMut, Mul, Neg, Sub};
10use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
11
12use crate::math::approx::ApproxEq;
13use crate::math::float::f32;
14use crate::math::space::{Affine, Linear, Proj4, Real};
15
16//
17// Types
18//
19
20/// A generic vector type. Represents an element of a vector space or a module,
21/// a generalization of a vector space where the scalars can be integers
22/// (technically, the scalar type can be any *ring*-like type).
23///
24/// # Type parameters
25/// * `Repr`: Representation of the scalar components of the vector,
26/// for example an array or a SIMD vector.
27/// * `Space`: The space that the vector is an element of. A tag type used to
28/// prevent mixing up vectors of different spaces and bases.
29///
30/// # Examples
31/// TODO
32#[repr(transparent)]
33pub struct Vector<Repr, Space = ()>(pub Repr, PhantomData<Space>);
34
35/// A 2-vector with `f32` components.
36pub type Vec2<Basis = ()> = Vector<[f32; 2], Real<2, Basis>>;
37/// A 2-vector with `f32` components.
38pub type Vec3<Basis = ()> = Vector<[f32; 3], Real<3, Basis>>;
39/// A `f32` 4-vector in the projective 3-space over โ„, aka P<sub>3</sub>(โ„).
40pub type ProjVec4 = Vector<[f32; 4], Proj4>;
41
42/// A 2-vector with `i32` components.
43pub type Vec2i<Basis = ()> = Vector<[i32; 2], Real<2, Basis>>;
44/// A 3-vector with `i32` components.
45pub type Vec3i<Basis = ()> = Vector<[i32; 3], Real<3, Basis>>;
46
47/// A 2-vector with `u32` components.
48pub type Vec2u<Basis = ()> = Vector<[u32; 2], Real<2, Basis>>;
49// Will add Vec3u if needed at some point.
50
51//
52// Free functions
53//
54
55/// Returns a real 2-vector with components `x` and `y`.
56pub const fn vec2<Sc, B>(x: Sc, y: Sc) -> Vector<[Sc; 2], Real<2, B>> {
57    Vector([x, y], PhantomData)
58}
59
60/// Returns a real 3-vector with components `x`, `y`, and `z`.
61pub const fn vec3<Sc, B>(x: Sc, y: Sc, z: Sc) -> Vector<[Sc; 3], Real<3, B>> {
62    Vector([x, y, z], PhantomData)
63}
64
65/// Returns a vector with all components equal to a scalar.
66///
67/// This operation is also called "broadcast".
68///
69/// # Examples
70/// ```
71/// # use retrofire_core::math::{vec3, Vec3};
72/// # use retrofire_core::math::vec::splat;
73/// let v: Vec3 = splat(1.23);
74/// assert_eq!(v, vec3(1.23, 1.23, 1.23));
75#[inline]
76pub fn splat<Sp, Sc: Clone, const DIM: usize>(s: Sc) -> Vector<[Sc; DIM], Sp> {
77    s.into()
78}
79
80//
81// Inherent impls
82//
83
84impl<R, Sp> Vector<R, Sp> {
85    /// Returns a new vector with representation `repr`.
86    #[inline]
87    pub const fn new(repr: R) -> Self {
88        Self(repr, PhantomData)
89    }
90
91    /// Returns a vector with value equal to `self` but in space `S`.
92    ///
93    /// This method can be used to coerce a vector from one space
94    /// to another in order to make types match. One use case is
95    /// to cast a "generic" vector returned by one of the constructor
96    /// functions to a more specific space.
97    // TODO Cannot be const (yet?) due to E0493 :(
98    #[inline]
99    pub fn to<S>(self) -> Vector<R, S> {
100        Vector::new(self.0)
101    }
102}
103
104// TODO Many of these functions could be more generic
105impl<Sp, const N: usize> Vector<[f32; N], Sp> {
106    /// Returns the length (magnitude) of `self`.
107    #[cfg(feature = "fp")]
108    #[inline]
109    pub fn len(&self) -> f32 {
110        super::float::f32::sqrt(self.dot(self))
111    }
112
113    /// Returns `self` normalized to unit length.
114    ///
115    /// # Examples
116    /// ```
117    /// # use retrofire_core::math::vec::*;
118    /// # use retrofire_core::assert_approx_eq;
119    /// let normalized: Vec2 = vec2(3.0, 4.0).normalize();
120    /// assert_approx_eq!(normalized, vec2(0.6, 0.8), eps=1e-2);
121    /// assert_approx_eq!(normalized.len_sqr(), 1.0, eps=1e-2);
122    /// ```
123    ///
124    /// # Panics
125    /// Panics in dev mode if `self` is a zero vector.
126    #[inline]
127    #[must_use]
128    pub fn normalize(&self) -> Self {
129        use super::float::f32;
130        #[cfg(feature = "std")]
131        use super::float::RecipSqrt;
132
133        let len_sqr = self.len_sqr();
134        debug_assert_ne!(len_sqr, 0.0, "cannot normalize a zero-length vector");
135        *self * f32::recip_sqrt(len_sqr)
136    }
137
138    /// Returns `self` clamped component-wise to the given range.
139    ///
140    /// In other words, for each component `self[i]`, the result `r` has
141    /// `r[i]` equal to `self[i].clamp(min[i], max[i])`.
142    ///
143    /// # Examples
144    /// ```
145    /// # use retrofire_core::math::vec::{vec3, Vec3, splat};
146    /// let v: Vec3 = vec3(0.5, 1.5, -2.0);
147    /// // Clamp to the unit cube
148    /// let v = v.clamp(&splat(-1.0), &splat(1.0));
149    /// assert_eq!(v, vec3(0.5, 1.0, -1.0));
150    #[must_use]
151    pub fn clamp(&self, min: &Self, max: &Self) -> Self {
152        array::from_fn(|i| self[i].clamp(min[i], max[i])).into()
153    }
154}
155
156impl<Sc, Sp, const N: usize> Vector<[Sc; N], Sp>
157where
158    Self: Linear<Scalar = Sc>,
159    Sc: Linear<Scalar = Sc> + Copy,
160{
161    /// Returns the length of `self`, squared.
162    ///
163    /// This avoids taking the square root in cases it's not needed and works with scalars for
164    /// which a square root is not defined.
165    #[inline]
166    pub fn len_sqr(&self) -> Sc {
167        self.dot(self)
168    }
169
170    /// Returns the dot product of `self` and `other`.
171    #[inline]
172    pub fn dot(&self, other: &Self) -> Sc {
173        self.0
174            .iter()
175            .zip(&other.0)
176            .map(|(a, b)| a.mul(*b))
177            .fold(Sc::zero(), |acc, x| acc.add(&x))
178    }
179
180    /// Returns the scalar projection of `self` onto `other`
181    /// (the length of the component of `self` parallel to `other`).
182    #[must_use]
183    pub fn scalar_project(&self, other: &Self) -> Sc
184    where
185        Sc: Div<Sc, Output = Sc>,
186    {
187        self.dot(other) / other.dot(other)
188    }
189    /// Returns the vector projection of `self` onto `other`
190    /// (the vector component of `self` parallel to `other`).
191    /// ```text
192    ///            self
193    ///            ^
194    ///           /.
195    ///         /  .
196    ///       /    .
197    ///     /      .
198    ///   /       _.
199    ///  +-------'->-----> other
200    ///         result
201    /// ```
202    #[must_use]
203    pub fn vector_project(&self, other: &Self) -> Self
204    where
205        Sc: Div<Sc, Output = Sc>,
206    {
207        other.mul(self.scalar_project(other))
208    }
209
210    /// Returns a vector of the same dimension as `self` by applying `f`
211    /// component-wise.
212    #[inline]
213    #[must_use]
214    pub fn map<T>(self, mut f: impl FnMut(Sc) -> T) -> Vector<[T; N], Sp> {
215        array::from_fn(|i| f(self[i])).into()
216    }
217}
218
219impl<R, Sc, B> Vector<R, Real<2, B>>
220where
221    R: Index<usize, Output = Sc>,
222    Sc: Copy,
223{
224    /// Returns the x component of `self`.
225    #[inline]
226    pub fn x(&self) -> Sc {
227        self.0[0]
228    }
229    /// Returns the y component of `self`.
230    #[inline]
231    pub fn y(&self) -> Sc {
232        self.0[1]
233    }
234}
235
236impl<R, Sc, B> Vector<R, Real<3, B>>
237where
238    R: Index<usize, Output = Sc>,
239    Sc: Copy,
240{
241    /// Returns the x component of `self`.
242    #[inline]
243    pub fn x(&self) -> Sc {
244        self.0[0]
245    }
246    /// Returns the y component of `self`.
247    #[inline]
248    pub fn y(&self) -> Sc {
249        self.0[1]
250    }
251    /// Returns the z component of `self`.
252    #[inline]
253    pub fn z(&self) -> Sc {
254        self.0[2]
255    }
256
257    /// Returns the cross product of `self` with `other`.
258    ///
259    /// The result is a vector perpendicular to both input vectors, its length
260    /// proportional to the area of the parallelogram formed by the vectors.
261    /// Specifically, the length is given by the identity:
262    ///
263    /// ```text
264    ///     |๐—ฎ ร— ๐—ฏ| = |๐—ฎ| |๐—ฏ| sin ๐œฝ
265    /// ```
266    ///
267    /// where |ยท| denotes the length of a vector and
268    /// ๐œฝ equals the angle between ๐—ฎ and ๐—ฏ.
269    ///
270    /// ```text
271    ///        ^
272    ///     r  |
273    ///     e  |
274    ///     s  |    other
275    ///     u  |     ^ - - - - - +
276    ///     l  |   /           /
277    ///     t  | /           /
278    ///        +-----------> self
279    /// ```
280    pub fn cross(&self, other: &Self) -> Self
281    where
282        Sc: Linear<Scalar = Sc>,
283        [Sc; 3]: Into<Self>,
284    {
285        let (s, o) = (self, other);
286        [
287            s.y().mul(o.z()).sub(&s.z().mul(o.y())),
288            s.z().mul(o.x()).sub(&s.x().mul(o.z())),
289            s.x().mul(o.y()).sub(&s.y().mul(o.x())),
290        ]
291        .into()
292    }
293}
294
295impl<R, Sc> Vector<R, Proj4>
296where
297    R: Index<usize, Output = Sc>,
298    Sc: Copy,
299{
300    /// Returns the x component of `self`.
301    #[inline]
302    pub fn x(&self) -> Sc {
303        self.0[0]
304    }
305    /// Returns the y component of `self`.
306    #[inline]
307    pub fn y(&self) -> Sc {
308        self.0[1]
309    }
310    /// Returns the z component of `self`.
311    #[inline]
312    pub fn z(&self) -> Sc {
313        self.0[2]
314    }
315    /// Returns the w component of `self`.
316    #[inline]
317    pub fn w(&self) -> Sc {
318        self.0[3]
319    }
320}
321
322//
323// Local trait impls
324//
325
326impl<Sc, Sp, const DIM: usize> Affine for Vector<[Sc; DIM], Sp>
327where
328    Sc: Affine,
329    Sc::Diff: Linear<Scalar = Sc::Diff> + Copy,
330{
331    type Space = Sp;
332    type Diff = Vector<[Sc::Diff; DIM], Sp>;
333
334    /// The dimension (number of components) of `Self`.
335    const DIM: usize = DIM;
336
337    #[inline]
338    fn add(&self, other: &Self::Diff) -> Self {
339        // TODO Profile performance of array::from_fn
340        array::from_fn(|i| self.0[i].add(&other.0[i])).into()
341    }
342    #[inline]
343    fn sub(&self, other: &Self) -> Self::Diff {
344        array::from_fn(|i| self.0[i].sub(&other.0[i])).into()
345    }
346}
347
348impl<Sc, Sp, const DIM: usize> Linear for Vector<[Sc; DIM], Sp>
349where
350    Self: Affine<Diff = Self>,
351    Sc: Linear<Scalar = Sc> + Copy,
352{
353    type Scalar = Sc;
354
355    /// Returns a vector with all-zero components, also called a null vector.
356    #[inline]
357    fn zero() -> Self {
358        [Sc::zero(); DIM].into()
359    }
360    #[inline]
361    fn neg(&self) -> Self {
362        array::from_fn(|i| self.0[i].neg()).into()
363    }
364    #[inline]
365    fn mul(&self, scalar: Self::Scalar) -> Self {
366        array::from_fn(|i| self.0[i].mul(scalar)).into()
367    }
368}
369
370impl<Sc: ApproxEq, Sp, const N: usize> ApproxEq<Self, Sc>
371    for Vector<[Sc; N], Sp>
372{
373    fn approx_eq_eps(&self, other: &Self, eps: &Sc) -> bool {
374        self.0.approx_eq_eps(&other.0, eps)
375    }
376    fn relative_epsilon() -> Sc {
377        Sc::relative_epsilon()
378    }
379}
380
381//
382// Foreign trait impls
383//
384
385// Manual impls of Copy, Clone, Eq, and PartialEq to avoid
386// superfluous where S: Trait bound
387
388impl<R: Copy, S> Copy for Vector<R, S> {}
389
390impl<R: Clone, S> Clone for Vector<R, S> {
391    fn clone(&self) -> Self {
392        Self(self.0.clone(), PhantomData)
393    }
394}
395
396impl<R: Default, S> Default for Vector<R, S> {
397    fn default() -> Self {
398        Self(R::default(), PhantomData)
399    }
400}
401
402impl<R: Eq, S> Eq for Vector<R, S> {}
403
404impl<R: PartialEq, S> PartialEq for Vector<R, S> {
405    fn eq(&self, other: &Self) -> bool {
406        self.0 == other.0
407    }
408}
409
410impl<const DIM: usize, B> Debug for Real<DIM, B>
411where
412    B: Debug + Default,
413{
414    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
415        const DIMS: [char; 3] = ['ยฒ', 'ยณ', 'โด'];
416        let b = B::default();
417        if let Some(dim) = DIMS.get(DIM - 2) {
418            write!(f, "โ„{dim}<{b:?}>")
419        } else {
420            write!(f, "โ„^{DIM}<{b:?}>")
421        }
422    }
423}
424
425impl<R: Debug, Sp: Debug + Default> Debug for Vector<R, Sp> {
426    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
427        write!(f, "Vec<{:?}>", Sp::default())?;
428        Debug::fmt(&self.0, f)
429    }
430}
431
432impl<R, Sp> From<R> for Vector<R, Sp> {
433    #[inline]
434    fn from(els: R) -> Self {
435        Self(els, PhantomData)
436    }
437}
438
439impl<Sp, Sc: Clone, const DIM: usize> From<Sc> for Vector<[Sc; DIM], Sp> {
440    /// Returns a vector with all components equal to `scalar`.
441    ///
442    /// This operation is also called "splat" or "broadcast".
443    #[inline]
444    fn from(scalar: Sc) -> Self {
445        array::from_fn(|_| scalar.clone()).into()
446    }
447}
448
449impl<R, Sp> Index<usize> for Vector<R, Sp>
450where
451    Self: Affine,
452    R: Index<usize>,
453{
454    type Output = R::Output;
455
456    /// Returns the component of `self` with index `i`.
457    ///
458    /// # Panics
459    /// If `i >= Self::DIM`.
460    /// Note that `Self::DIM` can be less than the number of elements in `R`.
461    #[inline]
462    fn index(&self, i: usize) -> &Self::Output {
463        assert!(i < Self::DIM, "index {i} out of bounds ({})", Self::DIM);
464        &self.0[i]
465    }
466}
467
468impl<R, Sp> IndexMut<usize> for Vector<R, Sp>
469where
470    Self: Affine,
471    R: IndexMut<usize>,
472{
473    /// Returns a mutable reference to the component of `self` with index `i`.
474    ///
475    /// # Panics
476    /// If `i >= Self::DIM`.
477    /// Note that `Self::DIM` can be less than the number of elements in `R`.
478    #[inline]
479    fn index_mut(&mut self, i: usize) -> &mut Self::Output {
480        assert!(i < Self::DIM, "index {i} out of bounds ({})", Self::DIM);
481        &mut self.0[i]
482    }
483}
484
485impl<R, Sp> Sum for Vector<R, Sp>
486where
487    Self: Linear,
488{
489    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
490        iter.fold(Self::zero(), |acc, v| Affine::add(&acc, &v))
491    }
492}
493
494//
495// Arithmetic traits
496//
497
498/// Implements an operator trait in terms of an op-assign trait.
499macro_rules! impl_op {
500    ($trait:ident :: $method:ident, $rhs:ty, $op:tt) => {
501        impl_op!($trait::$method, $rhs, $op, bound=Linear);
502    };
503    ($trait:ident :: $method:ident, $rhs:ty, $op:tt, bound=$bnd:path) => {
504        impl<R, Sp> $trait<$rhs> for Vector<R, Sp>
505        where
506            Self: $bnd,
507        {
508            type Output = Self;
509            /// TODO
510            #[inline]
511            fn $method(mut self, rhs: $rhs) -> Self {
512                self $op rhs; self
513            }
514        }
515    };
516}
517
518/// The vector += vector operator.
519impl<R, Sp> AddAssign<<Self as Affine>::Diff> for Vector<R, Sp>
520where
521    Self: Affine,
522{
523    #[inline]
524    fn add_assign(&mut self, rhs: <Self as Affine>::Diff) {
525        *self = Affine::add(&*self, &rhs);
526    }
527}
528// The vector + vector operator.
529impl_op!(Add::add, <Self as Affine>::Diff, +=, bound=Affine);
530
531/// The vector -= vector operator.
532impl<R, Sp> SubAssign<<Self as Affine>::Diff> for Vector<R, Sp>
533where
534    Self: Affine,
535{
536    #[inline]
537    fn sub_assign(&mut self, rhs: <Self as Affine>::Diff) {
538        *self = Affine::add(&*self, &rhs.neg());
539    }
540}
541
542// The vector - vector operator.
543impl_op!(Sub::sub, <Self as Affine>::Diff, -=, bound=Affine);
544
545// The vector *= scalar operator.
546impl<R, Sp> MulAssign<<Self as Linear>::Scalar> for Vector<R, Sp>
547where
548    Self: Linear,
549{
550    #[inline]
551    fn mul_assign(&mut self, rhs: <Self as Linear>::Scalar) {
552        *self = Linear::mul(&*self, rhs);
553    }
554}
555// The vector * scalar operator.
556impl_op!(Mul::mul, <Self as Linear>::Scalar, *=);
557
558// The vector /= scalar operator.
559impl<R, Sp> DivAssign<f32> for Vector<R, Sp>
560where
561    Self: Linear<Scalar = f32>,
562{
563    #[inline]
564    fn div_assign(&mut self, rhs: f32) {
565        debug_assert!(f32::abs(rhs) > 1e-7);
566        *self = Linear::mul(&*self, rhs.recip());
567    }
568}
569
570// The vector / scalar operator.
571impl_op!(Div::div, f32, /=, bound=Linear<Scalar = f32>);
572
573/// The vector negation operator.
574impl<R, Sp> Neg for Vector<R, Sp>
575where
576    Self: Linear,
577{
578    type Output = Self;
579
580    #[inline]
581    fn neg(self) -> Self::Output {
582        <Self as Linear>::neg(&self)
583    }
584}
585
586impl<R, Sp> Mul<Vector<R, Sp>> for f32
587where
588    Vector<R, Sp>: Linear<Scalar = f32>,
589{
590    type Output = Vector<R, Sp>;
591
592    #[inline]
593    fn mul(self, rhs: Vector<R, Sp>) -> Self::Output {
594        rhs * self
595    }
596}
597impl<R, Sp> Mul<Vector<R, Sp>> for i32
598where
599    Vector<R, Sp>: Linear<Scalar = i32>,
600{
601    type Output = Vector<R, Sp>;
602
603    #[inline]
604    fn mul(self, rhs: Vector<R, Sp>) -> Self::Output {
605        rhs * self
606    }
607}
608impl<R, Sp> Mul<Vector<R, Sp>> for u32
609where
610    Vector<R, Sp>: Linear<Scalar = u32>,
611{
612    type Output = Vector<R, Sp>;
613
614    #[inline]
615    fn mul(self, rhs: Vector<R, Sp>) -> Self::Output {
616        rhs * self
617    }
618}
619
620//
621// Unit tests
622//
623
624#[cfg(test)]
625mod tests {
626    use core::f32::consts::*;
627
628    use crate::assert_approx_eq;
629
630    use super::*;
631
632    pub const fn vec2<S>(x: S, y: S) -> Vector<[S; 2], Real<2>> {
633        super::vec2(x, y)
634    }
635    pub const fn vec3<S>(x: S, y: S, z: S) -> Vector<[S; 3], Real<3>> {
636        super::vec3(x, y, z)
637    }
638    pub const fn vec4<S>(x: S, y: S, z: S, w: S) -> Vector<[S; 4], Real<4>> {
639        Vector::new([x, y, z, w])
640    }
641
642    mod f32 {
643        use super::*;
644
645        #[cfg(feature = "fp")]
646        #[test]
647        fn length() {
648            assert_approx_eq!(vec2(1.0, 1.0).len(), SQRT_2);
649            assert_approx_eq!(vec2(-3.0, 4.0).len(), 5.0);
650            assert_approx_eq!(vec3(1.0, -2.0, 3.0).len(), 14.0f32.sqrt());
651        }
652
653        #[test]
654        fn length_squared() {
655            assert_eq!(vec2(1.0, 1.0).len_sqr(), 2.0);
656            assert_eq!(vec2(-4.0, 3.0).len_sqr(), 25.0);
657            assert_eq!(vec3(1.0, -2.0, 3.0).len_sqr(), 14.0);
658        }
659
660        #[test]
661        fn normalize() {
662            assert_approx_eq!(vec2(3.0, 4.0).normalize(), vec2(0.6, 0.8));
663
664            let sqrt_14 = 14.0f32.sqrt();
665            assert_approx_eq!(
666                vec3(1.0, 2.0, 3.0).normalize(),
667                vec3(1.0 / sqrt_14, 2.0 / sqrt_14, 3.0 / sqrt_14)
668            );
669        }
670
671        #[test]
672        fn vector_addition() {
673            assert_eq!(vec2(1.0, 2.0) + vec2(-2.0, 1.0), vec2(-1.0, 3.0));
674            assert_eq!(
675                vec3(1.0, 2.0, 0.0) + vec3(-2.0, 1.0, -1.0),
676                vec3(-1.0, 3.0, -1.0)
677            );
678        }
679
680        #[test]
681        fn scalar_multiplication() {
682            assert_eq!(vec2(1.0, -2.0) * 0.0, vec2(0.0, 0.0));
683            assert_eq!(vec3(1.0, -2.0, 3.0) * 3.0, vec3(3.0, -6.0, 9.0));
684            assert_eq!(3.0 * vec3(1.0, -2.0, 3.0), vec3(3.0, -6.0, 9.0));
685            assert_eq!(
686                vec4(1.0, -2.0, 0.0, -3.0) * 3.0,
687                vec4(3.0, -6.0, 0.0, -9.0)
688            );
689            assert_eq!(
690                3.0 * vec4(1.0, -2.0, 0.0, -3.0),
691                vec4(3.0, -6.0, 0.0, -9.0)
692            );
693        }
694
695        #[test]
696        fn scalar_division() {
697            assert_eq!(vec2(1.0, -2.0) / 1.0, vec2(1.0, -2.0));
698            assert_eq!(vec3(3.0, -6.0, 9.0) / 3.0, vec3(1.0, -2.0, 3.0));
699            assert_eq!(
700                vec4(3.0, -6.0, 0.0, -9.0) / 3.0,
701                vec4(1.0, -2.0, 0.0, -3.0)
702            );
703        }
704
705        #[test]
706        fn dot_product() {
707            assert_eq!(vec2(1.0, -2.0).dot(&vec2(2.0, 3.0)), -4.0);
708            assert_eq!(vec3(1.0, -2.0, 3.0).dot(&vec3(2.0, 3.0, -1.0)), -7.0);
709        }
710
711        #[test]
712        fn indexing() {
713            let mut v = vec2(1.0, 2.0);
714            assert_eq!(v[1], 2.0);
715            v[0] = 3.0;
716            assert_eq!(v.0, [3.0, 2.0]);
717
718            let mut v = vec3(1.0, 2.0, 3.0);
719            assert_eq!(v[1], 2.0);
720            v[2] = 4.0;
721            assert_eq!(v.0, [1.0, 2.0, 4.0]);
722        }
723
724        #[test]
725        fn from_array() {
726            assert_eq!(Vec2::from([1.0, -2.0]), vec2(1.0, -2.0));
727            assert_eq!(Vec3::from([1.0, -2.0, 4.0]), vec3(1.0, -2.0, 4.0));
728            assert_eq!(
729                Vector::from([1.0, -2.0, 4.0, -3.0]),
730                vec4(1.0, -2.0, 4.0, -3.0)
731            );
732        }
733    }
734
735    mod i32 {
736        use super::*;
737
738        #[test]
739        fn vector_addition() {
740            assert_eq!(vec2(1, 2) + vec2(-2, 1), vec2(-1, 3));
741            assert_eq!(vec3(1, 2, 0) + vec3(-2, 1, -1), vec3(-1, 3, -1));
742        }
743
744        #[test]
745        fn vector_subtraction() {
746            assert_eq!(vec2(1, 2) - vec2(-2, 3), vec2(3, -1));
747            assert_eq!(vec3(1, 2, 0) - vec3(-2, 1, 2), vec3(3, 1, -2));
748        }
749
750        #[test]
751        #[allow(clippy::erasing_op)]
752        fn scalar_multiplication() {
753            assert_eq!(vec2(1, -2) * 0, vec2(0, 0));
754
755            assert_eq!(vec3(1, -2, 3) * 3, vec3(3, -6, 9));
756            assert_eq!(3 * vec3(1, -2, 3), vec3(3, -6, 9));
757
758            assert_eq!(vec4(1, -2, 0, -3) * 3, vec4(3, -6, 0, -9));
759            assert_eq!(3 * vec4(1, -2, 0, -3), vec4(3, -6, 0, -9));
760        }
761
762        #[test]
763        fn dot_product() {
764            assert_eq!(vec2(1, -2).dot(&vec2(2, 3)), -4);
765            assert_eq!(vec3(1, -2, 3).dot(&vec3(2, 3, -1)), -7);
766        }
767
768        #[test]
769        fn indexing() {
770            let mut v = vec2(1, 2);
771            assert_eq!(v[1], 2);
772            v[0] = 3;
773            assert_eq!(v.0, [3, 2]);
774
775            let mut v = vec3(1, 2, 3);
776            assert_eq!(v[1], 2);
777            v[2] = 4;
778            assert_eq!(v.0, [1, 2, 4]);
779        }
780
781        #[test]
782        fn from_array() {
783            assert_eq!(Vec2i::from([1, -2]), vec2(1, -2));
784            assert_eq!(Vec3i::from([1, -2, 3]), vec3(1, -2, 3));
785        }
786    }
787
788    mod u32 {
789        use super::*;
790
791        #[test]
792        fn vector_addition() {
793            assert_eq!(vec2(1_u32, 2) + vec2(1_i32, -2), vec2(2_u32, 0));
794            assert_eq!(
795                vec3(1_u32, 2, 3) + vec3(-1_i32, 1, 0),
796                vec3(0_u32, 3, 3)
797            );
798        }
799
800        #[test]
801        fn vector_subtraction() {
802            assert_eq!(vec2(3_u32, 2) - vec2(3_i32, -1), vec2(0_u32, 3));
803            assert_eq!(
804                vec3(2_u32, 1, 3) - vec3(1_i32, -1, 0),
805                vec3(1_u32, 2, 3)
806            );
807        }
808
809        #[test]
810        fn indexing() {
811            let mut v = vec2(1u32, 2);
812            assert_eq!(v[1], 2);
813            v[0] = 3;
814            assert_eq!(v.0, [3, 2]);
815        }
816
817        #[test]
818        fn from_array() {
819            assert_eq!(Vec2u::from([1, 2]), vec2(1, 2));
820        }
821    }
822
823    #[test]
824    fn cross_product() {
825        assert_eq!(
826            vec3(1.0, 0.0, 0.0).cross(&vec3(0.0, 1.0, 0.0)),
827            vec3(0.0, 0.0, 1.0)
828        );
829        assert_eq!(
830            vec3(0.0, 0.0, 1.0).cross(&vec3(0.0, 1.0, 0.0)),
831            vec3(-1.0, 0.0, 0.0)
832        );
833    }
834
835    #[test]
836    fn iterator_sum() {
837        let vs = [vec2(-1.0, 2.0), vec2(0.0, 2.0), vec2(3.0, -1.0)];
838        assert_eq!(vs.into_iter().sum::<Vec2>(), vec2(2.0, 3.0));
839    }
840
841    #[test]
842    fn approx_equal_pass() {
843        assert_approx_eq!(vec2(1.0, -10.0), vec2(1.01, -9.9), eps = 0.011);
844    }
845    #[test]
846    #[should_panic]
847    fn approx_equal_fail() {
848        let eps = 2.0 * f32::relative_epsilon();
849        assert_approx_eq!(vec2(1.0, -10.0), vec2(1.0 + eps, -10.0 - eps));
850    }
851
852    // TODO Tests for projections
853
854    #[test]
855    fn debug() {
856        assert_eq!(
857            alloc::format!("{:?}", vec2(1.0, -E)),
858            "Vec<โ„ยฒ<()>>[1.0, -2.7182817]"
859        );
860        assert_eq!(
861            alloc::format!("{:?}", vec3(1.0, -2.0, 3.0)),
862            "Vec<โ„ยณ<()>>[1.0, -2.0, 3.0]"
863        );
864        assert_eq!(
865            alloc::format!("{:?}", vec4(1.0, -2.0, PI, -4.0)),
866            "Vec<โ„โด<()>>[1.0, -2.0, 3.1415927, -4.0]"
867        );
868    }
869}