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 + 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    /// Returns:
236    ///
237    /// The `norm_inf` function returns the maximum value between `self.x_` and `self.y_`.
238    ///
239    /// # Examples
240    ///
241    /// ```
242    /// use ginger::vector2::Vector2;
243    ///
244    /// let vector2 = &Vector2::new(3, -4);
245    /// assert_eq!(vector2.norm_inf(), 3);
246    /// ```
247    #[inline]
248    pub fn norm_inf(&self) -> T {
249        if self.x_ > self.y_ {
250            self.x_.clone()
251        } else {
252            self.y_.clone()
253        }
254    }
255}
256
257macro_rules! forward_xf_xf_binop {
258    (impl $imp:ident, $method:ident) => {
259        impl<'a, 'b, T: Clone + Num> $imp<&'b Vector2<T>> for &'a Vector2<T> {
260            type Output = Vector2<T>;
261
262            #[inline]
263            fn $method(self, other: &Vector2<T>) -> Self::Output {
264                self.clone().$method(other.clone())
265            }
266        }
267    };
268}
269
270macro_rules! forward_xf_val_binop {
271    (impl $imp:ident, $method:ident) => {
272        impl<'a, T: Clone + Num> $imp<Vector2<T>> for &'a Vector2<T> {
273            type Output = Vector2<T>;
274
275            #[inline]
276            fn $method(self, other: Vector2<T>) -> Self::Output {
277                self.clone().$method(other)
278            }
279        }
280    };
281}
282
283macro_rules! forward_val_xf_binop {
284    (impl $imp:ident, $method:ident) => {
285        impl<'a, T: Clone + Num> $imp<&'a Vector2<T>> for Vector2<T> {
286            type Output = Vector2<T>;
287
288            #[inline]
289            fn $method(self, other: &Vector2<T>) -> Self::Output {
290                self.$method(other.clone())
291            }
292        }
293    };
294}
295
296macro_rules! forward_all_binop {
297    (impl $imp:ident, $method:ident) => {
298        forward_xf_xf_binop!(impl $imp, $method);
299        forward_xf_val_binop!(impl $imp, $method);
300        forward_val_xf_binop!(impl $imp, $method);
301    };
302}
303
304// arithmetic
305forward_all_binop!(impl Add, add);
306
307/// Vector addition.
308///
309/// $$ \vec{a} + \vec{b} = (a_x + b_x,\; a_y + b_y) $$
310impl<T: Clone + Num> Add<Vector2<T>> for Vector2<T> {
311    type Output = Self;
312
313    #[inline]
314    fn add(self, other: Self) -> Self::Output {
315        Self::Output::new(self.x_ + other.x_, self.y_ + other.y_)
316    }
317}
318
319forward_all_binop!(impl Sub, sub);
320
321/// Vector subtraction.
322///
323/// $$ \vec{a} - \vec{b} = (a_x - b_x,\; a_y - b_y) $$
324impl<T: Clone + Num> Sub<Vector2<T>> for Vector2<T> {
325    type Output = Self;
326
327    #[inline]
328    fn sub(self, other: Self) -> Self::Output {
329        Self::Output::new(self.x_ - other.x_, self.y_ - other.y_)
330    }
331}
332
333// Op Assign
334
335mod opassign {
336    use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
337
338    use num_traits::NumAssign;
339
340    use crate::Vector2;
341
342    impl<T: Clone + NumAssign> AddAssign for Vector2<T> {
343        fn add_assign(&mut self, other: Self) {
344            self.x_ += other.x_;
345            self.y_ += other.y_;
346        }
347    }
348
349    impl<T: Clone + NumAssign> SubAssign for Vector2<T> {
350        fn sub_assign(&mut self, other: Self) {
351            self.x_ -= other.x_;
352            self.y_ -= other.y_;
353        }
354    }
355
356    impl<T: Clone + NumAssign> MulAssign<T> for Vector2<T> {
357        fn mul_assign(&mut self, other: T) {
358            self.x_ *= other.clone();
359            self.y_ *= other;
360        }
361    }
362
363    impl<T: Clone + NumAssign> DivAssign<T> for Vector2<T> {
364        fn div_assign(&mut self, other: T) {
365            self.x_ /= other.clone();
366            self.y_ /= other;
367        }
368    }
369
370    macro_rules! forward_op_assign1 {
371        (impl $imp:ident, $method:ident) => {
372            impl<'a, T: Clone + NumAssign> $imp<&'a Vector2<T>> for Vector2<T> {
373                #[inline]
374                fn $method(&mut self, other: &Self) {
375                    self.$method(other.clone())
376                }
377            }
378        };
379    }
380
381    macro_rules! forward_op_assign2 {
382        (impl $imp:ident, $method:ident) => {
383            impl<'a, T: Clone + NumAssign> $imp<&'a T> for Vector2<T> {
384                #[inline]
385                fn $method(&mut self, other: &T) {
386                    self.$method(other.clone())
387                }
388            }
389        };
390    }
391
392    forward_op_assign1!(impl AddAssign, add_assign);
393    forward_op_assign1!(impl SubAssign, sub_assign);
394    forward_op_assign2!(impl MulAssign, mul_assign);
395    forward_op_assign2!(impl DivAssign, div_assign);
396}
397
398/// Vector negation.
399///
400/// $$ -\vec{v} = (-v_x,\; -v_y) $$
401impl<T: Clone + Num + Neg<Output = T>> Neg for Vector2<T> {
402    type Output = Self;
403
404    #[inline]
405    fn neg(self) -> Self::Output {
406        Self::Output::new(-self.x_, -self.y_)
407    }
408}
409
410/// Vector negation (by reference).
411///
412/// $$ -\vec{v} = (-v_x,\; -v_y) $$
413impl<T: Clone + Num + Neg<Output = T>> Neg for &Vector2<T> {
414    type Output = Vector2<T>;
415
416    #[inline]
417    fn neg(self) -> Self::Output {
418        -self.clone()
419    }
420}
421
422macro_rules! scalar_arithmetic {
423    (@forward $imp:ident::$method:ident for $($scalar:ident),*) => (
424        impl<'a, T: Clone + Num> $imp<&'a T> for Vector2<T> {
425            type Output = Vector2<T>;
426
427            #[inline]
428            fn $method(self, other: &T) -> Self::Output {
429                self.$method(other.clone())
430            }
431        }
432        impl<'a, T: Clone + Num> $imp<T> for &'a Vector2<T> {
433            type Output = Vector2<T>;
434
435            #[inline]
436            fn $method(self, other: T) -> Self::Output {
437                self.clone().$method(other)
438            }
439        }
440        impl<'a, 'b, T: Clone + Num> $imp<&'a T> for &'b Vector2<T> {
441            type Output = Vector2<T>;
442
443            #[inline]
444            fn $method(self, other: &T) -> Self::Output {
445                self.clone().$method(other.clone())
446            }
447        }
448        $(
449            impl<'a> $imp<&'a Vector2<$scalar>> for $scalar {
450                type Output = Vector2<$scalar>;
451
452                #[inline]
453                fn $method(self, other: &Vector2<$scalar>) -> Vector2<$scalar> {
454                    self.$method(other.clone())
455                }
456            }
457            impl<'a> $imp<Vector2<$scalar>> for &'a $scalar {
458                type Output = Vector2<$scalar>;
459
460                #[inline]
461                fn $method(self, other: Vector2<$scalar>) -> Vector2<$scalar> {
462                    self.clone().$method(other)
463                }
464            }
465            impl<'a, 'b> $imp<&'a Vector2<$scalar>> for &'b $scalar {
466                type Output = Vector2<$scalar>;
467
468                #[inline]
469                fn $method(self, other: &Vector2<$scalar>) -> Vector2<$scalar> {
470                    self.clone().$method(other.clone())
471                }
472            }
473        )*
474    );
475    ($($scalar:ident),*) => (
476        scalar_arithmetic!(@forward Mul::mul for $($scalar),*);
477        // scalar_arithmetic!(@forward Div::div for $($scalar),*);
478        // scalar_arithmetic!(@forward Rem::rem for $($scalar),*);
479
480        $(
481            impl Mul<Vector2<$scalar>> for $scalar {
482                type Output = Vector2<$scalar>;
483
484                #[inline]
485                fn mul(self, other: Vector2<$scalar>) -> Self::Output {
486                    Self::Output::new(self * other.x_, self * other.y_)
487                }
488            }
489
490        )*
491    );
492}
493
494/// Scalar multiplication.
495///
496/// $$ \vec{v} \cdot s = (v_x \cdot s,\; v_y \cdot s) $$
497impl<T: Clone + Num> Mul<T> for Vector2<T> {
498    type Output = Vector2<T>;
499
500    #[inline]
501    fn mul(self, other: T) -> Self::Output {
502        Self::Output::new(self.x_ * other.clone(), self.y_ * other)
503    }
504}
505
506/// Scalar division.
507///
508/// $$ \vec{v} / s = (v_x / s,\; v_y / s) $$
509impl<T: Clone + Num> Div<T> for Vector2<T> {
510    type Output = Self;
511
512    #[inline]
513    fn div(self, other: T) -> Self::Output {
514        Self::Output::new(self.x_ / other.clone(), self.y_ / other)
515    }
516}
517
518/// Scalar remainder.
519///
520/// $$ \vec{v} \bmod s = (v_x \bmod s,\; v_y \bmod s) $$
521impl<T: Clone + Num> Rem<T> for Vector2<T> {
522    type Output = Vector2<T>;
523
524    #[inline]
525    fn rem(self, other: T) -> Self::Output {
526        Self::Output::new(self.x_ % other.clone(), self.y_ % other)
527    }
528}
529
530scalar_arithmetic!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64);
531
532// constants
533impl<T: Clone + Num> Zero for Vector2<T> {
534    /// The zero vector.
535    ///
536    /// $$ \vec{0} = (0, 0) $$
537    #[inline]
538    fn zero() -> Self {
539        Self::new(Zero::zero(), Zero::zero())
540    }
541
542    /// Returns `true` if this vector is the zero vector.
543    ///
544    /// $$ \vec{v} = \vec{0} \iff x = 0 \land y = 0 $$
545    #[inline]
546    fn is_zero(&self) -> bool {
547        self.x_.is_zero() && self.y_.is_zero()
548    }
549
550    #[inline]
551    fn set_zero(&mut self) {
552        self.x_.set_zero();
553        self.y_.set_zero();
554    }
555}
556
557// #[cfg(test)]
558// fn hash<T: hash::Hash>(x: &T) -> u64 {
559//     use std::collections::hash_map::RandomState;
560//     use std::hash::{BuildHasher, Hasher};
561//     let mut hasher = <RandomState as BuildHasher>::Hasher::new();
562//     x.hash(&mut hasher);
563//     hasher.finish()
564// }
565
566#[cfg(test)]
567mod test {
568    #![allow(non_upper_case_globals)]
569
570    // use super::{hash, Vector2};
571    use super::Vector2;
572    use core::f64;
573    use num_traits::Zero;
574
575    pub const _0_0v: Vector2<f64> = Vector2 { x_: 0.0, y_: 0.0 };
576    pub const _1_0v: Vector2<f64> = Vector2 { x_: 1.0, y_: 0.0 };
577    pub const _1_1v: Vector2<f64> = Vector2 { x_: 1.0, y_: 1.0 };
578    pub const _0_1v: Vector2<f64> = Vector2 { x_: 0.0, y_: 1.0 };
579    pub const _neg1_1v: Vector2<f64> = Vector2 { x_: -1.0, y_: 1.0 };
580    pub const _05_05v: Vector2<f64> = Vector2 { x_: 0.5, y_: 0.5 };
581    pub const all_consts: [Vector2<f64>; 5] = [_0_0v, _1_0v, _1_1v, _neg1_1v, _05_05v];
582    pub const _4_2v: Vector2<f64> = Vector2 { x_: 4.0, y_: 2.0 };
583
584    #[test]
585    fn test_consts() {
586        // check our constants are what Vector2::new creates
587        fn test(c: Vector2<f64>, r: f64, i: f64) {
588            assert_eq!(c, Vector2::new(r, i));
589        }
590        test(_0_0v, 0.0, 0.0);
591        test(_1_0v, 1.0, 0.0);
592        test(_1_1v, 1.0, 1.0);
593        test(_neg1_1v, -1.0, 1.0);
594        test(_05_05v, 0.5, 0.5);
595        assert_eq!(_0_0v, Zero::zero());
596    }
597
598    #[test]
599    fn test_scale_unscale() {
600        assert_eq!(_05_05v.scale(2.0), _1_1v);
601        assert_eq!(_1_1v.unscale(2.0), _05_05v);
602        for &c in all_consts.iter() {
603            assert_eq!(c.scale(2.0).unscale(2.0), c);
604        }
605    }
606
607    // #[test]
608    // fn test_hash() {
609    //     let a = Vector2::new(0i32, 0i32);
610    //     let b = Vector2::new(1i32, 0i32);
611    //     let c = Vector2::new(0i32, 1i32);
612    //     assert!(hash(&a) != hash(&b));
613    //     assert!(hash(&b) != hash(&c));
614    //     assert!(hash(&c) != hash(&a));
615    // }
616
617    #[test]
618    fn test_new() {
619        let v = Vector2::new(1, 2);
620        assert_eq!(v.x_, 1);
621        assert_eq!(v.y_, 2);
622    }
623
624    #[test]
625    fn test_dot() {
626        let v1 = Vector2::new(3, 4);
627        let v2 = Vector2::new(5, 6);
628        assert_eq!(v1.dot(&v2), 3 * 5 + 4 * 6);
629        assert_eq!(v1.dot(&v1), 3 * 3 + 4 * 4);
630    }
631
632    #[test]
633    fn test_cross() {
634        let v1 = Vector2::new(3, 4);
635        let v2 = Vector2::new(5, 6);
636        assert_eq!(v1.cross(&v2), 3 * 6 - 4 * 5);
637        assert_eq!(v1.cross(&v1), 0);
638    }
639
640    #[test]
641    fn test_norm_sqr() {
642        let v = Vector2::new(3, 4);
643        assert_eq!(v.norm_sqr(), 9 + 16);
644    }
645
646    #[test]
647    fn test_scale() {
648        let v = Vector2::new(3.0, 4.0);
649        assert_eq!(v.scale(2.0), Vector2::new(6.0, 8.0));
650        assert_eq!(v.scale(0.5), Vector2::new(1.5, 2.0));
651    }
652
653    #[test]
654    fn test_unscale() {
655        let v = Vector2::new(30, 40);
656        assert_eq!(v.unscale(10), Vector2::new(3, 4));
657    }
658
659    #[test]
660    fn test_l1_norm() {
661        let v = Vector2::new(3, -4);
662        assert_eq!(v.l1_norm(), 7);
663    }
664
665    #[test]
666    fn test_norm_inf() {
667        let v1 = Vector2::new(3, -4);
668        assert_eq!(v1.norm_inf(), 3);
669
670        let v2 = Vector2::new(5, 2);
671        assert_eq!(v2.norm_inf(), 5);
672    }
673
674    #[test]
675    fn test_add() {
676        let v1 = Vector2::new(1, 2);
677        let v2 = Vector2::new(3, 4);
678        assert_eq!(v1 + v2, Vector2::new(4, 6));
679
680        let v3 = v1 + v2;
681        assert_eq!(v3, Vector2::new(4, 6));
682
683        let v4 = v1 + v2;
684        assert_eq!(v4, Vector2::new(4, 6));
685    }
686
687    #[test]
688    fn test_sub() {
689        let v1 = Vector2::new(5, 6);
690        let v2 = Vector2::new(3, 4);
691        assert_eq!(v1 - v2, Vector2::new(2, 2));
692
693        let v3 = v1 - v2;
694        assert_eq!(v3, Vector2::new(2, 2));
695    }
696
697    #[test]
698    fn test_neg() {
699        let v = Vector2::new(1, -2);
700        assert_eq!(-v, Vector2::new(-1, 2));
701        assert_eq!(-&v, Vector2::new(-1, 2));
702    }
703
704    #[test]
705    fn test_scalar_mul() {
706        let v = Vector2::new(2, 3);
707        assert_eq!(v * 4, Vector2::new(8, 12));
708        assert_eq!(&v * 4, Vector2::new(8, 12));
709        assert_eq!(4 * v, Vector2::new(8, 12));
710        assert_eq!(4 * &v, Vector2::new(8, 12));
711    }
712
713    #[test]
714    fn test_scalar_div() {
715        let v = Vector2::new(10, 20);
716        assert_eq!(v / 5, Vector2::new(2, 4));
717    }
718
719    #[test]
720    fn test_scalar_rem() {
721        let v = Vector2::new(10, 21);
722        assert_eq!(v % 3, Vector2::new(1, 0));
723    }
724
725    #[test]
726    fn test_zero() {
727        let zero = Vector2::<i32>::zero();
728        assert_eq!(zero, Vector2::new(0, 0));
729        assert!(zero.is_zero());
730
731        let mut v = Vector2::new(1, 2);
732        assert!(!v.is_zero());
733        v.set_zero();
734        assert!(v.is_zero());
735    }
736
737    #[test]
738    fn test_add_assign() {
739        let mut v1 = Vector2::new(1, 2);
740        let v2 = Vector2::new(3, 4);
741        v1 += v2;
742        assert_eq!(v1, Vector2::new(4, 6));
743
744        let mut v3 = Vector2::new(1, 2);
745        v3 += &v2;
746        assert_eq!(v3, Vector2::new(4, 6));
747    }
748
749    #[test]
750    fn test_sub_assign() {
751        let mut v1 = Vector2::new(5, 6);
752        let v2 = Vector2::new(3, 4);
753        v1 -= v2;
754        assert_eq!(v1, Vector2::new(2, 2));
755
756        let mut v3 = Vector2::new(5, 6);
757        v3 -= &v2;
758        assert_eq!(v3, Vector2::new(2, 2));
759    }
760
761    #[test]
762    fn test_mul_assign() {
763        let mut v = Vector2::new(1, 2);
764        v *= 3;
765        assert_eq!(v, Vector2::new(3, 6));
766
767        let mut v2 = Vector2::new(1, 2);
768        let scalar = 3;
769        v2 *= &scalar;
770        assert_eq!(v2, Vector2::new(3, 6));
771    }
772
773    #[test]
774    fn test_div_assign() {
775        let mut v = Vector2::new(6, 9);
776        v /= 3;
777        assert_eq!(v, Vector2::new(2, 3));
778
779        let mut v2 = Vector2::new(6, 9);
780        let scalar = 3;
781        v2 /= &scalar;
782        assert_eq!(v2, Vector2::new(2, 3));
783    }
784
785    #[test]
786    fn test_float_operations() {
787        let v = Vector2::new(1.5, 2.5);
788        assert_eq!(v.scale(2.0), Vector2::new(3.0, 5.0));
789        assert_eq!(v.unscale(0.5), Vector2::new(3.0, 5.0));
790        assert_eq!(v.dot(&v), 1.5 * 1.5 + 2.5 * 2.5);
791    }
792
793    #[test]
794    fn test_clone_and_eq() {
795        let v1 = Vector2::new(1, 2);
796        let v2 = v1;
797        assert_eq!(v1, v2);
798
799        let v3 = Vector2::new(2, 1);
800        assert_ne!(v1, v3);
801    }
802
803    #[test]
804    fn test_debug() {
805        let v = Vector2::new(1, 2);
806        assert_eq!(format!("{:?}", v), "Vector2 { x_: 1, y_: 2 }");
807    }
808
809    #[test]
810    fn test_forward_xf_val_binop() {
811        let v1 = Vector2::new(1, 2);
812        let v2 = Vector2::new(3, 4);
813        let result: Vector2<i32> = v1 + v2;
814        assert_eq!(result, Vector2::new(4, 6));
815    }
816
817    #[test]
818    fn test_forward_val_xf_binop() {
819        let v1 = Vector2::new(1, 2);
820        let v2 = Vector2::new(3, 4);
821        let result: Vector2<i32> = v1 + v2;
822        assert_eq!(result, Vector2::new(4, 6));
823    }
824
825    #[test]
826    fn test_scalar_arithmetic_forward() {
827        let v = Vector2::new(2, 3);
828        let scalar = 5;
829        let result: Vector2<i32> = v * scalar;
830        assert_eq!(result, Vector2::new(10, 15));
831
832        let result2: Vector2<i32> = v * scalar;
833        assert_eq!(result2, Vector2::new(10, 15));
834
835        let result3: Vector2<i32> = 5 * &v;
836        assert_eq!(result3, Vector2::new(10, 15));
837    }
838
839    #[test]
840    fn test_scalar_left_mul() {
841        let v = Vector2::new(2, 3);
842        assert_eq!(5 * v, Vector2::new(10, 15));
843        assert_eq!(5 * &v, Vector2::new(10, 15));
844    }
845}
846
847#[cfg(test)]
848mod proptest {
849    use proptest::prelude::*;
850
851    use crate::Vector2;
852
853    const I32_BOUND: i32 = i32::MAX >> 8;
854
855    proptest! {
856        #[test]
857        fn test_add_commutative(a in -I32_BOUND..I32_BOUND, b in -I32_BOUND..I32_BOUND,
858                               c in -I32_BOUND..I32_BOUND, d in -I32_BOUND..I32_BOUND) {
859            let v1 = Vector2::new(a, b);
860            let v2 = Vector2::new(c, d);
861            prop_assert_eq!(v1 + v2, v2 + v1);
862        }
863
864        #[test]
865        fn test_sub_anti_commutative(a in -I32_BOUND..I32_BOUND, b in -I32_BOUND..I32_BOUND,
866                                     c in -I32_BOUND..I32_BOUND, d in -I32_BOUND..I32_BOUND) {
867            let v1 = Vector2::new(a, b);
868            let v2 = Vector2::new(c, d);
869            prop_assert_eq!(-(v2 - v1), v1 - v2);
870        }
871
872        #[test]
873        fn test_mul_scalar_distributive(a in -1000..1000, b in -1000..1000, s in -100..100) {
874            let v = Vector2::new(a, b);
875            prop_assert_eq!(v * s, Vector2::new(a * s, b * s));
876        }
877
878        #[test]
879        fn test_scale_unscale_roundtrip(a in -1e10f64..1e10f64, b in -1e10f64..1e10f64,
880                                        s in -1e5f64..1e5f64) {
881            let s = if s.abs() < 1e-10 { 1.0 } else { s };
882            let v = Vector2::new(a, b);
883            let scaled = v.scale(s);
884            let unscaled = scaled.unscale(s);
885            prop_assert!((unscaled.x_ - a).abs() / a.abs() < 1e-10 || a.abs() < 1e-10);
886            prop_assert!((unscaled.y_ - b).abs() / b.abs() < 1e-10 || b.abs() < 1e-10);
887        }
888
889        #[test]
890        fn test_dot_commutative(a in -1000..1000, b in -1000..1000,
891                                c in -1000..1000, d in -1000..1000) {
892            let v1 = Vector2::new(a, b);
893            let v2 = Vector2::new(c, d);
894            prop_assert_eq!(v1.dot(&v2), v2.dot(&v1));
895        }
896
897        #[test]
898        fn test_neg_involution(a in -I32_BOUND..I32_BOUND, b in -I32_BOUND..I32_BOUND) {
899            let v = Vector2::new(a, b);
900            prop_assert_eq!(-(-v), v);
901        }
902    }
903}