Skip to main content

ginger/
vector2.rs

1// #![no_std]
2use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
3use num_traits::{Num, Signed, Zero};
4
5/// The `Vector2` struct represents a 2-dimensional vector with elements of type `T`.
6///
7/// Properties:
8///
9/// * `x_`: The `x_` property represents the first element of the `Vector2` object. It is of type `T`,
10///   which means it can be any type that is specified when creating an instance of `Vector2`.
11/// * `y_`: The `y_` property is the second element of the `Vector2` object. It represents the
12///   y-coordinate of a 2D vector.
13///
14/// # Examples:
15///
16/// ```
17/// use ginger::vector2::Vector2;
18///
19/// assert_eq!(Vector2::new(3, 4), Vector2 { x_: 3, y_: 4});
20/// ```
21#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug, Default)]
22pub struct Vector2<T> {
23    /// The first element of the vector2 object
24    pub x_: T,
25    /// The second element of the vector2 object
26    pub y_: T,
27}
28
29impl<T> Vector2<T> {
30    /// Creates a new [`Vector2<T>`].
31    ///
32    /// The `new` function creates a new `Vector2` instance with the given `x` and `y` values.
33    ///
34    /// Arguments:
35    ///
36    /// * `x_`: The parameter `x_` represents the x-coordinate of the vector. It is of type `T`, which means
37    ///   it can be any type that implements the necessary operations for vector calculations (e.g., addition,
38    ///   subtraction, multiplication).
39    /// * `y_`: The `y_` parameter represents the y-coordinate of the vector.
40    ///
41    /// Returns:
42    ///
43    /// The `new` function returns a new instance of the `Vector2<T>` struct.
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// use ginger::vector2::Vector2;
49    ///
50    /// assert_eq!(Vector2::new(3, 4), Vector2 { x_: 3, y_: 4});
51    /// ```
52    #[inline]
53    pub const fn new(x_: T, y_: T) -> Self {
54        Vector2 { x_, y_ }
55    }
56}
57
58impl<T: Clone + Num> Vector2<T> {
59    /// The `dot` function calculates the dot product of two vectors.
60    ///
61    /// $$ \mathbf{v}_1 \cdot \mathbf{v}_2 = x_1 x_2 + y_1 y_2 $$
62    ///
63    /// Arguments:
64    ///
65    /// * `other`: The `other` parameter is a reference to another `Vector2` object that we want to
66    ///   calculate the dot product with.
67    ///
68    /// Returns:
69    ///
70    /// The dot product of two vectors is being returned.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use ginger::vector2::Vector2;
76    ///
77    /// let vector2 = &Vector2::new(3, 4);
78    /// let other = &Vector2::new(5, 6);
79    /// assert_eq!(vector2.dot(other), 15 + 24);
80    /// assert_eq!(vector2.dot(&vector2), 9 + 16);
81    /// ```
82    #[inline]
83    pub fn dot(&self, other: &Self) -> T {
84        self.x_.clone() * other.x_.clone() + self.y_.clone() * other.y_.clone()
85    }
86
87    /// The `cross` function calculates the cross product of two vectors.
88    ///
89    /// $$ \mathbf{v}_1 \times \mathbf{v}_2 = x_1 y_2 - y_1 x_2 $$
90    ///
91    /// Arguments:
92    ///
93    /// * `other`: The `other` parameter is a reference to another `Vector2` object that we want to
94    ///   calculate the cross product with.
95    ///
96    /// Returns:
97    ///
98    /// The cross product of two vectors is being returned.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use ginger::vector2::Vector2;
104    ///
105    /// let vector2 = &Vector2::new(3, 4);
106    /// let other = &Vector2::new(5, 6);
107    /// assert_eq!(vector2.cross(other), 18 - 20);
108    /// assert_eq!(vector2.cross(&vector2), 0);
109    /// ```
110    #[inline]
111    pub fn cross(&self, other: &Self) -> T {
112        self.x_.clone() * other.y_.clone() - self.y_.clone() * other.x_.clone()
113    }
114
115    /// Returns the norm sqr of this [`Vector2<T>`].
116    ///
117    /// $$ \|\mathbf{v}\|^2 = x^2 + y^2 $$
118    ///
119    /// The `norm_sqr` function calculates the squared norm of a `Vector2` object.
120    ///
121    /// Returns:
122    ///
123    /// The `norm_sqr` function returns the squared norm of the `Vector2<T>`.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// use ginger::vector2::Vector2;
129    ///
130    /// let vector2 = &Vector2::new(3, 4);
131    /// assert_eq!(vector2.norm_sqr(), 9 + 16);
132    /// ```
133    #[inline]
134    pub fn norm_sqr(&self) -> T {
135        self.dot(self)
136    }
137
138    /// The `scale` function multiplies the x and y components of a `Vector2` object by a given scalar
139    /// value.
140    ///
141    /// Arguments:
142    ///
143    /// * `alpha`: The parameter `alpha` represents the scaling factor that will be applied to the vector.
144    ///
145    /// Returns:
146    ///
147    /// The `scale` method returns a new `Vector2` object.
148    ///
149    /// # Examples
150    ///
151    /// ```
152    /// use ginger::vector2::Vector2;
153    ///
154    /// let vector2 = &Vector2::new(3.0, 4.0);
155    /// assert_eq!(vector2.scale(10.0), Vector2::new(30.0, 40.0));
156    /// assert_eq!(vector2.scale(0.5), Vector2::new(1.5, 2.0));
157    /// ```
158    #[inline]
159    pub fn scale(&self, alpha: T) -> Self {
160        Self::new(self.x_.clone() * alpha.clone(), self.y_.clone() * alpha)
161    }
162
163    /// The `unscale` function divides the x and y components of a `Vector2` by a given value.
164    ///
165    /// Arguments:
166    ///
167    /// * `alpha`: The `alpha` parameter is a value of type `T` that is used to divide the `x_` and `y_`
168    ///   values of the `Vector2` object.
169    ///
170    /// Returns:
171    ///
172    /// The `unscale` method returns a new `Vector2` object.
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// use ginger::vector2::Vector2;
178    ///
179    /// let vector2 = &Vector2::new(30, 40);
180    /// assert_eq!(vector2.unscale(10), Vector2::new(3, 4));
181    /// ```
182    #[inline]
183    pub fn unscale(&self, alpha: T) -> Self {
184        Self::new(self.x_.clone() / alpha.clone(), self.y_.clone() / alpha)
185    }
186}
187
188impl<T: Clone + Signed> Vector2<T> {
189    /// The `l1_norm` function calculates the Manhattan distance from the origin for a 2D vector.
190    ///
191    /// $$ \|\mathbf{v}\|_1 = |x| + |y| $$
192    ///
193    /// [Manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
194    ///
195    /// Returns:
196    ///
197    /// The function `l1_norm` returns the L1 norm of a `Vector2` object, which is the sum of the absolute
198    /// values of its `x_` and `y_` components.
199    ///
200    /// # Examples
201    ///
202    /// ```
203    /// use ginger::vector2::Vector2;
204    ///
205    /// let vector2 = &Vector2::new(3, -4);
206    /// assert_eq!(vector2.l1_norm(), 7);
207    /// ```
208    #[inline]
209    pub fn l1_norm(&self) -> T {
210        self.x_.abs() + self.y_.abs()
211    }
212}
213
214impl<T: Clone + PartialOrd> Vector2<T> {
215    /// The `norm_inf` function returns the maximum absolute value of the two elements in a `Vector2`
216    /// object.
217    ///
218    /// Returns:
219    ///
220    /// The `norm_inf` function returns the maximum value between `self.x_` and `self.y_`.
221    ///
222    /// # Examples
223    ///
224    /// ```
225    /// use ginger::vector2::Vector2;
226    ///
227    /// let vector2 = &Vector2::new(3, -4);
228    /// assert_eq!(vector2.norm_inf(), 3);
229    /// ```
230    #[inline]
231    pub fn norm_inf(&self) -> T {
232        if self.x_ > self.y_ {
233            self.x_.clone()
234        } else {
235            self.y_.clone()
236        }
237    }
238}
239
240macro_rules! forward_xf_xf_binop {
241    (impl $imp:ident, $method:ident) => {
242        impl<'a, 'b, T: Clone + Num> $imp<&'b Vector2<T>> for &'a Vector2<T> {
243            type Output = Vector2<T>;
244
245            #[inline]
246            fn $method(self, other: &Vector2<T>) -> Self::Output {
247                self.clone().$method(other.clone())
248            }
249        }
250    };
251}
252
253macro_rules! forward_xf_val_binop {
254    (impl $imp:ident, $method:ident) => {
255        impl<'a, T: Clone + Num> $imp<Vector2<T>> for &'a Vector2<T> {
256            type Output = Vector2<T>;
257
258            #[inline]
259            fn $method(self, other: Vector2<T>) -> Self::Output {
260                self.clone().$method(other)
261            }
262        }
263    };
264}
265
266macro_rules! forward_val_xf_binop {
267    (impl $imp:ident, $method:ident) => {
268        impl<'a, T: Clone + Num> $imp<&'a Vector2<T>> for Vector2<T> {
269            type Output = Vector2<T>;
270
271            #[inline]
272            fn $method(self, other: &Vector2<T>) -> Self::Output {
273                self.$method(other.clone())
274            }
275        }
276    };
277}
278
279macro_rules! forward_all_binop {
280    (impl $imp:ident, $method:ident) => {
281        forward_xf_xf_binop!(impl $imp, $method);
282        forward_xf_val_binop!(impl $imp, $method);
283        forward_val_xf_binop!(impl $imp, $method);
284    };
285}
286
287// arithmetic
288forward_all_binop!(impl Add, add);
289
290// (a, b) + (c, d) == (a + c), (b + d)
291impl<T: Clone + Num> Add<Vector2<T>> for Vector2<T> {
292    type Output = Self;
293
294    #[inline]
295    fn add(self, other: Self) -> Self::Output {
296        Self::Output::new(self.x_ + other.x_, self.y_ + other.y_)
297    }
298}
299
300forward_all_binop!(impl Sub, sub);
301
302// (a, b) - (c, d) == (a - c), (b - d)
303impl<T: Clone + Num> Sub<Vector2<T>> for Vector2<T> {
304    type Output = Self;
305
306    #[inline]
307    fn sub(self, other: Self) -> Self::Output {
308        Self::Output::new(self.x_ - other.x_, self.y_ - other.y_)
309    }
310}
311
312// Op Assign
313
314mod opassign {
315    use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
316
317    use num_traits::NumAssign;
318
319    use crate::Vector2;
320
321    impl<T: Clone + NumAssign> AddAssign for Vector2<T> {
322        fn add_assign(&mut self, other: Self) {
323            self.x_ += other.x_;
324            self.y_ += other.y_;
325        }
326    }
327
328    impl<T: Clone + NumAssign> SubAssign for Vector2<T> {
329        fn sub_assign(&mut self, other: Self) {
330            self.x_ -= other.x_;
331            self.y_ -= other.y_;
332        }
333    }
334
335    impl<T: Clone + NumAssign> MulAssign<T> for Vector2<T> {
336        fn mul_assign(&mut self, other: T) {
337            self.x_ *= other.clone();
338            self.y_ *= other;
339        }
340    }
341
342    impl<T: Clone + NumAssign> DivAssign<T> for Vector2<T> {
343        fn div_assign(&mut self, other: T) {
344            self.x_ /= other.clone();
345            self.y_ /= other;
346        }
347    }
348
349    macro_rules! forward_op_assign1 {
350        (impl $imp:ident, $method:ident) => {
351            impl<'a, T: Clone + NumAssign> $imp<&'a Vector2<T>> for Vector2<T> {
352                #[inline]
353                fn $method(&mut self, other: &Self) {
354                    self.$method(other.clone())
355                }
356            }
357        };
358    }
359
360    macro_rules! forward_op_assign2 {
361        (impl $imp:ident, $method:ident) => {
362            impl<'a, T: Clone + NumAssign> $imp<&'a T> for Vector2<T> {
363                #[inline]
364                fn $method(&mut self, other: &T) {
365                    self.$method(other.clone())
366                }
367            }
368        };
369    }
370
371    forward_op_assign1!(impl AddAssign, add_assign);
372    forward_op_assign1!(impl SubAssign, sub_assign);
373    forward_op_assign2!(impl MulAssign, mul_assign);
374    forward_op_assign2!(impl DivAssign, div_assign);
375}
376
377impl<T: Clone + Num + Neg<Output = T>> Neg for Vector2<T> {
378    type Output = Self;
379
380    #[inline]
381    fn neg(self) -> Self::Output {
382        Self::Output::new(-self.x_, -self.y_)
383    }
384}
385
386impl<T: Clone + Num + Neg<Output = T>> Neg for &Vector2<T> {
387    type Output = Vector2<T>;
388
389    #[inline]
390    fn neg(self) -> Self::Output {
391        -self.clone()
392    }
393}
394
395macro_rules! scalar_arithmetic {
396    (@forward $imp:ident::$method:ident for $($scalar:ident),*) => (
397        impl<'a, T: Clone + Num> $imp<&'a T> for Vector2<T> {
398            type Output = Vector2<T>;
399
400            #[inline]
401            fn $method(self, other: &T) -> Self::Output {
402                self.$method(other.clone())
403            }
404        }
405        impl<'a, T: Clone + Num> $imp<T> for &'a Vector2<T> {
406            type Output = Vector2<T>;
407
408            #[inline]
409            fn $method(self, other: T) -> Self::Output {
410                self.clone().$method(other)
411            }
412        }
413        impl<'a, 'b, T: Clone + Num> $imp<&'a T> for &'b Vector2<T> {
414            type Output = Vector2<T>;
415
416            #[inline]
417            fn $method(self, other: &T) -> Self::Output {
418                self.clone().$method(other.clone())
419            }
420        }
421        $(
422            impl<'a> $imp<&'a Vector2<$scalar>> for $scalar {
423                type Output = Vector2<$scalar>;
424
425                #[inline]
426                fn $method(self, other: &Vector2<$scalar>) -> Vector2<$scalar> {
427                    self.$method(other.clone())
428                }
429            }
430            impl<'a> $imp<Vector2<$scalar>> for &'a $scalar {
431                type Output = Vector2<$scalar>;
432
433                #[inline]
434                fn $method(self, other: Vector2<$scalar>) -> Vector2<$scalar> {
435                    self.clone().$method(other)
436                }
437            }
438            impl<'a, 'b> $imp<&'a Vector2<$scalar>> for &'b $scalar {
439                type Output = Vector2<$scalar>;
440
441                #[inline]
442                fn $method(self, other: &Vector2<$scalar>) -> Vector2<$scalar> {
443                    self.clone().$method(other.clone())
444                }
445            }
446        )*
447    );
448    ($($scalar:ident),*) => (
449        scalar_arithmetic!(@forward Mul::mul for $($scalar),*);
450        // scalar_arithmetic!(@forward Div::div for $($scalar),*);
451        // scalar_arithmetic!(@forward Rem::rem for $($scalar),*);
452
453        $(
454            impl Mul<Vector2<$scalar>> for $scalar {
455                type Output = Vector2<$scalar>;
456
457                #[inline]
458                fn mul(self, other: Vector2<$scalar>) -> Self::Output {
459                    Self::Output::new(self * other.x_, self * other.y_)
460                }
461            }
462
463        )*
464    );
465}
466
467impl<T: Clone + Num> Mul<T> for Vector2<T> {
468    type Output = Vector2<T>;
469
470    #[inline]
471    fn mul(self, other: T) -> Self::Output {
472        Self::Output::new(self.x_ * other.clone(), self.y_ * other)
473    }
474}
475
476impl<T: Clone + Num> Div<T> for Vector2<T> {
477    type Output = Self;
478
479    #[inline]
480    fn div(self, other: T) -> Self::Output {
481        Self::Output::new(self.x_ / other.clone(), self.y_ / other)
482    }
483}
484
485impl<T: Clone + Num> Rem<T> for Vector2<T> {
486    type Output = Vector2<T>;
487
488    #[inline]
489    fn rem(self, other: T) -> Self::Output {
490        Self::Output::new(self.x_ % other.clone(), self.y_ % other)
491    }
492}
493
494scalar_arithmetic!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64);
495
496// constants
497impl<T: Clone + Num> Zero for Vector2<T> {
498    #[inline]
499    fn zero() -> Self {
500        Self::new(Zero::zero(), Zero::zero())
501    }
502
503    #[inline]
504    fn is_zero(&self) -> bool {
505        self.x_.is_zero() && self.y_.is_zero()
506    }
507
508    #[inline]
509    fn set_zero(&mut self) {
510        self.x_.set_zero();
511        self.y_.set_zero();
512    }
513}
514
515// #[cfg(test)]
516// fn hash<T: hash::Hash>(x: &T) -> u64 {
517//     use std::collections::hash_map::RandomState;
518//     use std::hash::{BuildHasher, Hasher};
519//     let mut hasher = <RandomState as BuildHasher>::Hasher::new();
520//     x.hash(&mut hasher);
521//     hasher.finish()
522// }
523
524#[cfg(test)]
525mod test {
526    #![allow(non_upper_case_globals)]
527
528    // use super::{hash, Vector2};
529    use super::Vector2;
530    use core::f64;
531    use num_traits::Zero;
532
533    pub const _0_0v: Vector2<f64> = Vector2 { x_: 0.0, y_: 0.0 };
534    pub const _1_0v: Vector2<f64> = Vector2 { x_: 1.0, y_: 0.0 };
535    pub const _1_1v: Vector2<f64> = Vector2 { x_: 1.0, y_: 1.0 };
536    pub const _0_1v: Vector2<f64> = Vector2 { x_: 0.0, y_: 1.0 };
537    pub const _neg1_1v: Vector2<f64> = Vector2 { x_: -1.0, y_: 1.0 };
538    pub const _05_05v: Vector2<f64> = Vector2 { x_: 0.5, y_: 0.5 };
539    pub const all_consts: [Vector2<f64>; 5] = [_0_0v, _1_0v, _1_1v, _neg1_1v, _05_05v];
540    pub const _4_2v: Vector2<f64> = Vector2 { x_: 4.0, y_: 2.0 };
541
542    #[test]
543    fn test_consts() {
544        // check our constants are what Vector2::new creates
545        fn test(c: Vector2<f64>, r: f64, i: f64) {
546            assert_eq!(c, Vector2::new(r, i));
547        }
548        test(_0_0v, 0.0, 0.0);
549        test(_1_0v, 1.0, 0.0);
550        test(_1_1v, 1.0, 1.0);
551        test(_neg1_1v, -1.0, 1.0);
552        test(_05_05v, 0.5, 0.5);
553        assert_eq!(_0_0v, Zero::zero());
554    }
555
556    #[test]
557    fn test_scale_unscale() {
558        assert_eq!(_05_05v.scale(2.0), _1_1v);
559        assert_eq!(_1_1v.unscale(2.0), _05_05v);
560        for &c in all_consts.iter() {
561            assert_eq!(c.scale(2.0).unscale(2.0), c);
562        }
563    }
564
565    // #[test]
566    // fn test_hash() {
567    //     let a = Vector2::new(0i32, 0i32);
568    //     let b = Vector2::new(1i32, 0i32);
569    //     let c = Vector2::new(0i32, 1i32);
570    //     assert!(hash(&a) != hash(&b));
571    //     assert!(hash(&b) != hash(&c));
572    //     assert!(hash(&c) != hash(&a));
573    // }
574
575    #[test]
576    fn test_new() {
577        let v = Vector2::new(1, 2);
578        assert_eq!(v.x_, 1);
579        assert_eq!(v.y_, 2);
580    }
581
582    #[test]
583    fn test_dot() {
584        let v1 = Vector2::new(3, 4);
585        let v2 = Vector2::new(5, 6);
586        assert_eq!(v1.dot(&v2), 3 * 5 + 4 * 6);
587        assert_eq!(v1.dot(&v1), 3 * 3 + 4 * 4);
588    }
589
590    #[test]
591    fn test_cross() {
592        let v1 = Vector2::new(3, 4);
593        let v2 = Vector2::new(5, 6);
594        assert_eq!(v1.cross(&v2), 3 * 6 - 4 * 5);
595        assert_eq!(v1.cross(&v1), 0);
596    }
597
598    #[test]
599    fn test_norm_sqr() {
600        let v = Vector2::new(3, 4);
601        assert_eq!(v.norm_sqr(), 9 + 16);
602    }
603
604    #[test]
605    fn test_scale() {
606        let v = Vector2::new(3.0, 4.0);
607        assert_eq!(v.scale(2.0), Vector2::new(6.0, 8.0));
608        assert_eq!(v.scale(0.5), Vector2::new(1.5, 2.0));
609    }
610
611    #[test]
612    fn test_unscale() {
613        let v = Vector2::new(30, 40);
614        assert_eq!(v.unscale(10), Vector2::new(3, 4));
615    }
616
617    #[test]
618    fn test_l1_norm() {
619        let v = Vector2::new(3, -4);
620        assert_eq!(v.l1_norm(), 7);
621    }
622
623    #[test]
624    fn test_norm_inf() {
625        let v1 = Vector2::new(3, -4);
626        assert_eq!(v1.norm_inf(), 3);
627
628        let v2 = Vector2::new(5, 2);
629        assert_eq!(v2.norm_inf(), 5);
630    }
631
632    #[test]
633    fn test_add() {
634        let v1 = Vector2::new(1, 2);
635        let v2 = Vector2::new(3, 4);
636        assert_eq!(v1 + v2, Vector2::new(4, 6));
637
638        let v3 = v1 + v2;
639        assert_eq!(v3, Vector2::new(4, 6));
640
641        let v4 = v1 + v2;
642        assert_eq!(v4, Vector2::new(4, 6));
643    }
644
645    #[test]
646    fn test_sub() {
647        let v1 = Vector2::new(5, 6);
648        let v2 = Vector2::new(3, 4);
649        assert_eq!(v1 - v2, Vector2::new(2, 2));
650
651        let v3 = v1 - v2;
652        assert_eq!(v3, Vector2::new(2, 2));
653    }
654
655    #[test]
656    fn test_neg() {
657        let v = Vector2::new(1, -2);
658        assert_eq!(-v, Vector2::new(-1, 2));
659        assert_eq!(-&v, Vector2::new(-1, 2));
660    }
661
662    #[test]
663    fn test_scalar_mul() {
664        let v = Vector2::new(2, 3);
665        assert_eq!(v * 4, Vector2::new(8, 12));
666        assert_eq!(&v * 4, Vector2::new(8, 12));
667        assert_eq!(4 * v, Vector2::new(8, 12));
668        assert_eq!(4 * &v, Vector2::new(8, 12));
669    }
670
671    #[test]
672    fn test_scalar_div() {
673        let v = Vector2::new(10, 20);
674        assert_eq!(v / 5, Vector2::new(2, 4));
675    }
676
677    #[test]
678    fn test_scalar_rem() {
679        let v = Vector2::new(10, 21);
680        assert_eq!(v % 3, Vector2::new(1, 0));
681    }
682
683    #[test]
684    fn test_zero() {
685        let zero = Vector2::<i32>::zero();
686        assert_eq!(zero, Vector2::new(0, 0));
687        assert!(zero.is_zero());
688
689        let mut v = Vector2::new(1, 2);
690        assert!(!v.is_zero());
691        v.set_zero();
692        assert!(v.is_zero());
693    }
694
695    #[test]
696    fn test_add_assign() {
697        let mut v1 = Vector2::new(1, 2);
698        let v2 = Vector2::new(3, 4);
699        v1 += v2;
700        assert_eq!(v1, Vector2::new(4, 6));
701
702        let mut v3 = Vector2::new(1, 2);
703        v3 += &v2;
704        assert_eq!(v3, Vector2::new(4, 6));
705    }
706
707    #[test]
708    fn test_sub_assign() {
709        let mut v1 = Vector2::new(5, 6);
710        let v2 = Vector2::new(3, 4);
711        v1 -= v2;
712        assert_eq!(v1, Vector2::new(2, 2));
713
714        let mut v3 = Vector2::new(5, 6);
715        v3 -= &v2;
716        assert_eq!(v3, Vector2::new(2, 2));
717    }
718
719    #[test]
720    fn test_mul_assign() {
721        let mut v = Vector2::new(1, 2);
722        v *= 3;
723        assert_eq!(v, Vector2::new(3, 6));
724
725        let mut v2 = Vector2::new(1, 2);
726        let scalar = 3;
727        v2 *= &scalar;
728        assert_eq!(v2, Vector2::new(3, 6));
729    }
730
731    #[test]
732    fn test_div_assign() {
733        let mut v = Vector2::new(6, 9);
734        v /= 3;
735        assert_eq!(v, Vector2::new(2, 3));
736
737        let mut v2 = Vector2::new(6, 9);
738        let scalar = 3;
739        v2 /= &scalar;
740        assert_eq!(v2, Vector2::new(2, 3));
741    }
742
743    #[test]
744    fn test_float_operations() {
745        let v = Vector2::new(1.5, 2.5);
746        assert_eq!(v.scale(2.0), Vector2::new(3.0, 5.0));
747        assert_eq!(v.unscale(0.5), Vector2::new(3.0, 5.0));
748        assert_eq!(v.dot(&v), 1.5 * 1.5 + 2.5 * 2.5);
749    }
750
751    #[test]
752    fn test_clone_and_eq() {
753        let v1 = Vector2::new(1, 2);
754        let v2 = v1;
755        assert_eq!(v1, v2);
756
757        let v3 = Vector2::new(2, 1);
758        assert_ne!(v1, v3);
759    }
760
761    #[test]
762    fn test_debug() {
763        let v = Vector2::new(1, 2);
764        assert_eq!(format!("{:?}", v), "Vector2 { x_: 1, y_: 2 }");
765    }
766
767    #[test]
768    fn test_forward_xf_val_binop() {
769        let v1 = Vector2::new(1, 2);
770        let v2 = Vector2::new(3, 4);
771        let result: Vector2<i32> = v1 + v2;
772        assert_eq!(result, Vector2::new(4, 6));
773    }
774
775    #[test]
776    fn test_forward_val_xf_binop() {
777        let v1 = Vector2::new(1, 2);
778        let v2 = Vector2::new(3, 4);
779        let result: Vector2<i32> = v1 + v2;
780        assert_eq!(result, Vector2::new(4, 6));
781    }
782
783    #[test]
784    fn test_scalar_arithmetic_forward() {
785        let v = Vector2::new(2, 3);
786        let scalar = 5;
787        let result: Vector2<i32> = v * scalar;
788        assert_eq!(result, Vector2::new(10, 15));
789
790        let result2: Vector2<i32> = v * scalar;
791        assert_eq!(result2, Vector2::new(10, 15));
792
793        let result3: Vector2<i32> = 5 * &v;
794        assert_eq!(result3, Vector2::new(10, 15));
795    }
796
797    #[test]
798    fn test_scalar_left_mul() {
799        let v = Vector2::new(2, 3);
800        assert_eq!(5 * v, Vector2::new(10, 15));
801        assert_eq!(5 * &v, Vector2::new(10, 15));
802    }
803}
804
805#[cfg(test)]
806mod proptest {
807    use proptest::prelude::*;
808
809    use crate::Vector2;
810
811    const I32_BOUND: i32 = i32::MAX >> 8;
812
813    proptest! {
814        #[test]
815        fn test_add_commutative(a in -I32_BOUND..I32_BOUND, b in -I32_BOUND..I32_BOUND,
816                               c in -I32_BOUND..I32_BOUND, d in -I32_BOUND..I32_BOUND) {
817            let v1 = Vector2::new(a, b);
818            let v2 = Vector2::new(c, d);
819            prop_assert_eq!(v1 + v2, v2 + v1);
820        }
821
822        #[test]
823        fn test_sub_anti_commutative(a in -I32_BOUND..I32_BOUND, b in -I32_BOUND..I32_BOUND,
824                                     c in -I32_BOUND..I32_BOUND, d in -I32_BOUND..I32_BOUND) {
825            let v1 = Vector2::new(a, b);
826            let v2 = Vector2::new(c, d);
827            prop_assert_eq!(-(v2 - v1), v1 - v2);
828        }
829
830        #[test]
831        fn test_mul_scalar_distributive(a in -1000..1000, b in -1000..1000, s in -100..100) {
832            let v = Vector2::new(a, b);
833            prop_assert_eq!(v * s, Vector2::new(a * s, b * s));
834        }
835
836        #[test]
837        fn test_scale_unscale_roundtrip(a in -1e10f64..1e10f64, b in -1e10f64..1e10f64,
838                                        s in -1e5f64..1e5f64) {
839            let s = if s.abs() < 1e-10 { 1.0 } else { s };
840            let v = Vector2::new(a, b);
841            let scaled = v.scale(s);
842            let unscaled = scaled.unscale(s);
843            prop_assert!((unscaled.x_ - a).abs() / a.abs() < 1e-10 || a.abs() < 1e-10);
844            prop_assert!((unscaled.y_ - b).abs() / b.abs() < 1e-10 || b.abs() < 1e-10);
845        }
846
847        #[test]
848        fn test_dot_commutative(a in -1000..1000, b in -1000..1000,
849                                c in -1000..1000, d in -1000..1000) {
850            let v1 = Vector2::new(a, b);
851            let v2 = Vector2::new(c, d);
852            prop_assert_eq!(v1.dot(&v2), v2.dot(&v1));
853        }
854
855        #[test]
856        fn test_neg_involution(a in -I32_BOUND..I32_BOUND, b in -I32_BOUND..I32_BOUND) {
857            let v = Vector2::new(a, b);
858            prop_assert_eq!(-(-v), v);
859        }
860    }
861}