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