Implemented more operators for point
[kaka/rust-sdl-test.git] / src / common.rs
1 use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg};
2
3 pub type Nanoseconds = u64;
4
5 #[macro_export]
6 macro_rules! point {
7     ( $x:expr, $y:expr ) => {
8         Point2D { x: $x, y: $y }
9     };
10 }
11
12 #[derive(Debug, Default, Copy, Clone, PartialEq)]
13 pub struct Point2D<T> {
14     pub x: T,
15     pub y: T,
16 }
17
18 impl Point2D<f64> {
19     pub fn length(self) -> f64 {
20         ((self.x * self.x) + (self.y * self.y)).sqrt()
21     }
22 }
23
24 ////////// add point to point //////////////////////////////////////////////////
25 impl<T: Add<Output = T>> Add for Point2D<T> {
26     type Output = Self;
27
28     fn add(self, rhs: Self) -> Self {
29         Self {
30             x: self.x + rhs.x,
31             y: self.y + rhs.y,
32         }
33     }
34 }
35
36 impl<T: Add<Output = T> + Copy> AddAssign for Point2D<T> {
37     fn add_assign(&mut self, rhs: Self) {
38         *self = Self {
39             x: self.x + rhs.x,
40             y: self.y + rhs.y,
41         }
42     }
43 }
44
45 ////////// add tuple to point //////////////////////////////////////////////////
46 impl<T: Add<Output = T>> Add<(T, T)> for Point2D<T> {
47     type Output = Self;
48
49     fn add(self, rhs: (T, T)) -> Self {
50         Self {
51             x: self.x + rhs.0,
52             y: self.y + rhs.1,
53         }
54     }
55 }
56
57 ////////// subtract point from point ///////////////////////////////////////////
58 impl<T: Sub<Output = T>> Sub for Point2D<T> {
59     type Output = Self;
60
61     fn sub(self, rhs: Self) -> Self {
62         Self {
63             x: self.x - rhs.x,
64             y: self.y - rhs.y,
65         }
66     }
67 }
68
69 impl<T: Sub<Output = T> + Copy> SubAssign for Point2D<T> {
70     fn sub_assign(&mut self, rhs: Self) {
71         *self = Self {
72             x: self.x - rhs.x,
73             y: self.y - rhs.y,
74         }
75     }
76 }
77
78 ////////// multiply point with scalar //////////////////////////////////////////
79 impl<T: Mul<Output = T> + Copy> Mul<T> for Point2D<T> {
80     type Output = Self;
81
82     fn mul(self, rhs: T) -> Self {
83         Self {
84             x: self.x * rhs,
85             y: self.y * rhs,
86         }
87     }
88 }
89
90 impl<T: Mul<Output = T> + Copy> MulAssign<T> for Point2D<T> {
91     fn mul_assign(&mut self, rhs: T) {
92         *self = Self {
93             x: self.x * rhs,
94             y: self.y * rhs,
95         }
96     }
97 }
98
99 ////////// multiply components of two points ///////////////////////////////////
100 impl<T: Mul<Output = T>> Mul for Point2D<T> {
101     type Output = Self;
102
103     fn mul(self, rhs: Self) -> Self {
104         Self {
105             x: self.x * rhs.x,
106             y: self.y * rhs.y,
107         }
108     }
109 }
110
111 impl<T: Mul<Output = T> + Copy> MulAssign for Point2D<T> {
112     fn mul_assign(&mut self, rhs: Self) {
113         *self = Self {
114             x: self.x * rhs.x,
115             y: self.y * rhs.y,
116         }
117     }
118 }
119
120 ////////// divide point with scalar ////////////////////////////////////////////
121 impl<T: Div<Output = T> + Copy> Div<T> for Point2D<T> {
122     type Output = Self;
123
124     fn div(self, rhs: T) -> Self {
125         Self {
126             x: self.x / rhs,
127             y: self.y / rhs,
128         }
129     }
130 }
131
132 impl<T: Div<Output = T> + Copy> DivAssign<T> for Point2D<T> {
133     fn div_assign(&mut self, rhs: T) {
134         *self = Self {
135             x: self.x / rhs,
136             y: self.y / rhs,
137         }
138     }
139 }
140
141 ////////// divide components of two points /////////////////////////////////////
142 impl<T: Div<Output = T>> Div for Point2D<T> {
143     type Output = Self;
144
145     fn div(self, rhs: Self) -> Self {
146         Self {
147             x: self.x / rhs.x,
148             y: self.y / rhs.y,
149         }
150     }
151 }
152
153 impl<T: Div<Output = T> + Copy> DivAssign for Point2D<T> {
154     fn div_assign(&mut self, rhs: Self) {
155         *self = Self {
156             x: self.x / rhs.x,
157             y: self.y / rhs.y,
158         }
159     }
160 }
161
162 impl<T: Neg<Output = T>> Neg for Point2D<T> {
163     type Output = Self;
164
165     fn neg(self) -> Self {
166         Self {
167             x: -self.x,
168             y: -self.y,
169         }
170     }
171 }
172
173 impl<T> From<(T, T)> for Point2D<T> {
174     fn from(item: (T, T)) -> Self {
175         Point2D {
176             x: item.0,
177             y: item.1,
178         }
179     }
180 }
181
182 #[macro_export]
183 macro_rules! rect {
184     ( $x:expr, $y:expr ) => {
185         Rect { x: $x, y: $y }
186     };
187 }
188
189 #[derive(Default)]
190 pub struct Rect<T> {
191     pub width: T,
192     pub height: T,
193 }
194
195 impl<T: Mul<Output = T> + Copy> Rect<T> {
196     #[allow(dead_code)]
197     pub fn area(&self) -> T {
198         self.width * self.height
199     }
200 }
201
202 impl<T> From<(T, T)> for Rect<T> {
203     fn from(item: (T, T)) -> Self {
204         Rect {
205             width: item.0,
206             height: item.1,
207         }
208     }
209 }
210
211 #[cfg(test)]
212 mod tests {
213     use super::*;
214
215     #[test]
216     fn immutable_copy_of_point() {
217         let a = point!(0, 0);
218         let mut b = a; // Copy
219         assert_eq!(a, b); // PartialEq
220         b.x = 1;
221         assert_ne!(a, b); // PartialEq
222     }
223
224     #[test]
225     fn add_points() {
226         let mut a = point!(1, 0);
227         assert_eq!(a + point!(2, 2), point!(3, 2)); // Add
228         a += point!(2, 2); // AddAssign
229         assert_eq!(a, point!(3, 2));
230         assert_eq!(point!(1, 0) + (2, 3), point!(3, 3));
231     }
232
233     #[test]
234     fn sub_points() {
235         let mut a = point!(1, 0);
236         assert_eq!(a - point!(2, 2), point!(-1, -2));
237         a -= point!(2, 2);
238         assert_eq!(a, point!(-1, -2));
239     }
240
241     #[test]
242     fn mul_points() {
243         let mut a = point!(1, 2);
244         assert_eq!(a * 2, point!(2, 4));
245         assert_eq!(a * point!(2, 3), point!(2, 6));
246         a *= 2;
247         assert_eq!(a, point!(2, 4));
248         a *= point!(3, 1);
249         assert_eq!(a, point!(6, 4));
250     }
251
252     #[test]
253     fn div_points() {
254         let mut a = point!(4, 8);
255         assert_eq!(a / 2, point!(2, 4));
256         assert_eq!(a / point!(2, 4), point!(2, 2));
257         a /= 2;
258         assert_eq!(a, point!(2, 4));
259         a /= point!(2, 4);
260         assert_eq!(a, point!(1, 1));
261     }
262
263     #[test]
264     fn neg_point() {
265         assert_eq!(point!(1, 1), -point!(-1, -1));
266     }
267
268     #[test]
269     fn area_for_rect_of_multipliable_type() {
270         let r: Rect<_> = (30, 20).into(); // the Into trait uses the From trait
271         assert_eq!(r.area(), 30 * 20);
272         // let a = Rect::from(("a".to_string(), "b".to_string())).area(); // this doesn't work, because area() is not implemented for String
273     }
274 }