use std::ops::{Add, AddAssign, Mul}; pub type Nanoseconds = u64; #[macro_export] macro_rules! point { ( $x:expr, $y:expr ) => { Point2D { x: $x, y: $y } }; } #[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct Point2D { pub x: T, pub y: T, } impl Point2D { pub fn length(self) -> f64 { ((self.x * self.x) + (self.y * self.y)).sqrt() } } impl> Add for Point2D { type Output = Point2D; fn add(self, rhs: Point2D) -> Self::Output { Point2D { x: self.x + rhs.x, y: self.y + rhs.y, } } } impl AddAssign for Point2D { fn add_assign(&mut self, rhs: Point2D) { self.x += rhs.x; self.y += rhs.y; } } impl From<(T, T)> for Point2D { fn from(item: (T, T)) -> Self { Point2D { x: item.0, y: item.1, } } } #[macro_export] macro_rules! rect { ( $x:expr, $y:expr ) => { Rect { x: $x, y: $y } }; } #[derive(Default)] pub struct Rect { pub width: T, pub height: T, } impl + Copy> Rect { #[allow(dead_code)] pub fn area(&self) -> T { self.width * self.height } } impl From<(T, T)> for Rect { fn from(item: (T, T)) -> Self { Rect { width: item.0, height: item.1, } } } #[cfg(test)] mod tests { use super::*; #[test] fn immutable_copy_of_point() { let a = point!(0, 0); let mut b = a; // Copy assert_eq!(a, b); // PartialEq b.x = 1; assert_ne!(a, b); // PartialEq } #[test] fn add_points() { let mut a = point!(1, 0); assert_eq!(a + point!(2, 2), point!(3, 2)); // Add a += point!(2, 2); // AddAssign assert_eq!(a, point!(3, 2)); } #[test] fn area_for_rect_of_multipliable_type() { let r: Rect<_> = (30, 20).into(); // the Into trait uses the From trait assert_eq!(r.area(), 30 * 20); // let a = Rect::from(("a".to_string(), "b".to_string())).area(); // this doesn't work, because area() is not implemented for String } }