1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// Basicly a glorified tuple
pub struct Vec2d<T> {
    /// x
    pub x: T,
    /// y
    pub y: T,
}

/// Vec2d<u32>
pub type Vu2d = Vec2d<u32>;
/// Vec2d<i32>
pub type Vi2d = Vec2d<i32>;
/// Vec2d<f32>
pub type Vf2d = Vec2d<f32>;

impl<T> Vec2d<T> {
    /// Cast the Vec2d to an other Vec2d with a differant inner type
    #[inline]
    pub fn cast<U: From<T>>(self) -> Vec2d<U> {
        let x: U = self.x.into();
        let y: U = self.y.into();
        Vec2d { x, y }
    }
}

//impl<T> Vec2d<T> where T: Add<T> + Sub<T> + Div<T> + Mul<T> {

//}

impl<T: Copy> Vec2d<T>
where
    T: Add<Output = T>
        + Sub<Output = T>
        + Mul<Output = T>
        + Div<Output = T>
        + Neg<Output = T>
        + Into<f32>
        + From<f32>,
{
    /// Return the magnitude (hypotenus) of the given Vec2d as f64
    pub fn mag_f64(&self) -> f32 {
        let mag2: f32 = self.mag2().into();
        mag2.sqrt()
    }
    /// Return the magnitude (hypotenus) of the given Vec2d as T
    pub fn mag(&self) -> T {
        let mag2: f32 = self.mag2().into();
        mag2.sqrt().into()
    }

    /// Return the magnitude (hypotenus) of the given Vec2d as T without doing the square root
    pub fn mag2(&self) -> T {
        self.x * self.x + self.y * self.y
    }

    /// Return a normalized version of the Vec2d
    #[must_use]
    pub fn norm(&self) -> Self {
        let r: T = self.mag_f64().recip().into();
        Vec2d {
            x: self.x * r,
            y: self.y * r,
        }
    }

    /// Return the normal of the given Vec2d
    #[must_use]
    pub fn perp(&self) -> Self {
        Vec2d {
            x: -self.y,
            y: self.x,
        }
    }

    /// Perform the dot product on the Vec2ds
    pub fn dot(&self, rhs: &Self) -> T {
        self.x + rhs.x + self.y + rhs.y
    }

    /// Perform the cross product on the Vec2ds
    pub fn cross(&self, rhs: &Self) -> T {
        self.x + rhs.x - self.y + rhs.y
    }
}

macro_rules! operator {
    ($trait:tt, $operator:tt, $func_name:ident) => {
        impl<T:Copy> $trait for Vec2d<T> where T: $trait<Output = T>, {
            type Output = Self;
            fn $func_name(self, rhs: Self) -> Self::Output {
                Vec2d { x: self.x $operator rhs.x, y: self.y $operator rhs.y}
            }
        }
    };
    ($trait:tt, $operator:tt, $func_name:ident, $type:ty) => {
        impl<T:Copy> $trait<$type> for Vec2d<T> where T: $trait<Output = T>, {
            type Output = Self;
            fn $func_name(self, rhs: $type) -> Self::Output {
                Vec2d { x: self.x $operator rhs, y: self.y $operator rhs}
            }
        }
    };
}
macro_rules! operator_assign {
    ($trait:tt, $operator:tt, $func_name:ident) => {
        impl<T:Copy> $trait for Vec2d<T> where T: $trait<T>, {
            fn $func_name(&mut self, rhs: Self){
                self.x $operator rhs.x; self.y $operator rhs.y;
            }
            }
        };
    ($trait:tt, $operator:tt, $func_name:ident, $type:ty) => {
        impl<T:Copy> $trait<$type> for Vec2d<T> where T: $trait<T>, {
            fn $func_name(&mut self, rhs: $type){
                self.x $operator rhs; self.y $operator rhs;
            }
            }
        };
}

macro_rules! cast {
    ($from:ty, $to:ty) => {
        impl Vec2d<$from> {
            paste! {
                #[must_use] pub fn [<cast _$to>](self) -> Vec2d<$to> {
                    Vec2d {
                        x: self.x as $to,
                        y: self.y as $to,
                    }
                }
            }
        }
    };
}

operator!(Add, + , add);
operator!(Sub, - , sub);
operator!(Mul, * , mul);
operator!(Div, / , div);
operator!(Mul, * , mul, T);
operator!(Div, / , div, T);
operator_assign!(AddAssign, += , add_assign);
operator_assign!(SubAssign, -= , sub_assign);
operator_assign!(MulAssign, *= , mul_assign, T);
operator_assign!(DivAssign, /= , div_assign, T);

cast!(u32, f32);
cast!(i32, f32);

cast!(f32, u32);
cast!(i32, u32);

cast!(f32, i32);
cast!(u32, i32);

impl<T: Copy> From<(T, T)> for Vec2d<T> {
    fn from(t: (T, T)) -> Self {
        Vec2d { x: t.0, y: t.1 }
    }
}
impl<T: Copy> From<[T; 2]> for Vec2d<T> {
    fn from(t: [T; 2]) -> Self {
        Vec2d { x: t[0], y: t[1] }
    }
}