Repository: bitshifter/glam-rs
Pull request #134 (2021-02-28 00:19:24)

Impl Eq and Hash for ivec and uvec
This implements Eq and Hash for integer Vec2/3/4 which is a very convenient pair of traits to have.


Patch:
diff --git a/src/vec.rs b/src/vec.rs
index 96c6ed9..bb40fa7 100644
--- a/src/vec.rs
+++ b/src/vec.rs
@@ -604,6 +604,19 @@ macro_rules! impl_vecn_common_traits {
     };
 }
 
+macro_rules! impl_vecn_eq_hash_traits {
+    ($t:ty, $size:literal, $vecn:ident) => {
+        impl Eq for $vecn {}
+
+        impl core::hash::Hash for $vecn {
+            fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+                let inner: &[$t; $size] = self.as_ref();
+                inner.hash(state);
+            }
+        }
+    };
+}
+
 // Adds signed vector trait implementations.
 // The traits here should be supported for signed types of $t and all sizes of vector.
 macro_rules! impl_vecn_signed_traits {
diff --git a/src/vec2.rs b/src/vec2.rs
index d60ee4b..3f3ae45 100644
--- a/src/vec2.rs
+++ b/src/vec2.rs
@@ -201,6 +201,7 @@ impl IVec2 {
     impl_vecn_as_u32!(UVec2, x, y);
 }
 impl_vec2_signed_traits!(i32, ivec2, IVec2, IVec3, BVec2, XYI32);
+impl_vecn_eq_hash_traits!(i32, 2, IVec2);
 
 type XYU32 = XY<u32>;
 
@@ -216,3 +217,4 @@ impl UVec2 {
     impl_vecn_as_i32!(IVec2, x, y);
 }
 impl_vec2_unsigned_traits!(u32, uvec2, UVec2, UVec3, BVec2, XYU32);
+impl_vecn_eq_hash_traits!(u32, 2, UVec2);
diff --git a/src/vec3.rs b/src/vec3.rs
index 157701a..be1abfe 100644
--- a/src/vec3.rs
+++ b/src/vec3.rs
@@ -341,6 +341,7 @@ impl IVec3 {
 }
 impl_vec3_common_traits!(i32, ivec3, IVec2, IVec3, IVec4, BVec3, XYZI32);
 impl_vecn_signed_traits!(i32, 3, IVec3, XYZI32, SignedVector3);
+impl_vecn_eq_hash_traits!(i32, 3, IVec3);
 
 type XYZU32 = XYZ<u32>;
 
@@ -356,6 +357,7 @@ impl UVec3 {
     impl_vecn_as_i32!(IVec3, x, y, z);
 }
 impl_vec3_common_traits!(u32, uvec3, UVec2, UVec3, UVec4, BVec3, XYZU32);
+impl_vecn_eq_hash_traits!(u32, 3, UVec3);
 
 #[test]
 fn test_vec3_private() {
diff --git a/src/vec4.rs b/src/vec4.rs
index ce4c9af..f0ed1ff 100644
--- a/src/vec4.rs
+++ b/src/vec4.rs
@@ -271,6 +271,7 @@ impl IVec4 {
     impl_vecn_as_u32!(UVec4, x, y, z, w);
 }
 impl_vec4_signed_traits!(i32, ivec4, IVec2, IVec3, IVec4, BVec4, XYZWI32);
+impl_vecn_eq_hash_traits!(i32, 4, IVec4);
 
 type XYZWU32 = XYZW<u32>;
 
@@ -286,6 +287,7 @@ impl UVec4 {
     impl_vecn_as_i32!(IVec4, x, y, z, w);
 }
 impl_vec4_common_traits!(u32, uvec4, UVec2, UVec3, UVec4, BVec4, XYZWU32);
+impl_vecn_eq_hash_traits!(u32, 4, UVec4);
 
 #[test]
 fn test_vec4_private() {


Test patch:
diff --git a/tests/vec2.rs b/tests/vec2.rs
index cf7963d..4bfa56d 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -403,6 +403,38 @@ macro_rules! impl_vec2_signed_tests {
     };
 }
 
+macro_rules! impl_vec2_eq_hash_tests {
+    ($t:ident, $new:ident) => {
+        #[test]
+        fn test_ve2_hash() {
+            use std::collections::hash_map::DefaultHasher;
+            use std::hash::Hash;
+            use std::hash::Hasher;
+
+            let a = $new(1 as $t, 2 as $t);
+            let b = $new(1 as $t, 2 as $t);
+            let c = $new(3 as $t, 2 as $t);
+
+            let mut hasher = DefaultHasher::new();
+            a.hash(&mut hasher);
+            let a_hashed = hasher.finish();
+
+            let mut hasher = DefaultHasher::new();
+            b.hash(&mut hasher);
+            let b_hashed = hasher.finish();
+
+            let mut hasher = DefaultHasher::new();
+            c.hash(&mut hasher);
+            let c_hashed = hasher.finish();
+
+            assert_eq!(a, b);
+            assert_eq!(a_hashed, b_hashed);
+            assert_ne!(a, c);
+            assert_ne!(a_hashed, c_hashed);
+        }
+    };
+}
+
 macro_rules! impl_vec2_float_tests {
     ($t:ident, $const_new:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $mat2:ident) => {
         impl_vec2_signed_tests!($t, $const_new, $new, $vec2, $vec3, $mask);
@@ -685,6 +717,7 @@ mod ivec2 {
     }
 
     impl_vec2_signed_tests!(i32, const_ivec2, ivec2, IVec2, IVec3, BVec2);
+    impl_vec2_eq_hash_tests!(i32, ivec2);
 }
 
 mod uvec2 {
@@ -700,4 +733,5 @@ mod uvec2 {
     }
 
     impl_vec2_tests!(u32, const_uvec2, uvec2, UVec2, UVec3, BVec2);
+    impl_vec2_eq_hash_tests!(u32, uvec2);
 }
diff --git a/tests/vec3.rs b/tests/vec3.rs
index e0d8b0b..5c766c3 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -448,6 +448,38 @@ macro_rules! impl_vec3_signed_tests {
     };
 }
 
+macro_rules! impl_vec3_eq_hash_tests {
+    ($t:ident, $new:ident) => {
+        #[test]
+        fn test_vec3_hash() {
+            use std::collections::hash_map::DefaultHasher;
+            use std::hash::Hash;
+            use std::hash::Hasher;
+
+            let a = $new(1 as $t, 2 as $t, 3 as $t);
+            let b = $new(1 as $t, 2 as $t, 3 as $t);
+            let c = $new(3 as $t, 2 as $t, 1 as $t);
+
+            let mut hasher = DefaultHasher::new();
+            a.hash(&mut hasher);
+            let a_hashed = hasher.finish();
+
+            let mut hasher = DefaultHasher::new();
+            b.hash(&mut hasher);
+            let b_hashed = hasher.finish();
+
+            let mut hasher = DefaultHasher::new();
+            c.hash(&mut hasher);
+            let c_hashed = hasher.finish();
+
+            assert_eq!(a, b);
+            assert_eq!(a_hashed, b_hashed);
+            assert_ne!(a, c);
+            assert_ne!(a_hashed, c_hashed);
+        }
+    };
+}
+
 macro_rules! impl_vec3_float_tests {
     ($t:ident, $const_new:ident, $new:ident, $vec3:ident, $mask:ident) => {
         impl_vec3_signed_tests!($t, $const_new, $new, $vec3, $mask);
@@ -853,6 +885,7 @@ mod ivec3 {
     }
 
     impl_vec3_signed_tests!(i32, const_ivec3, ivec3, IVec3, BVec3);
+    impl_vec3_eq_hash_tests!(i32, ivec3);
 }
 
 mod uvec3 {
@@ -868,4 +901,5 @@ mod uvec3 {
     }
 
     impl_vec3_tests!(u32, const_uvec3, uvec3, UVec3, BVec3);
+    impl_vec3_eq_hash_tests!(u32, uvec3);
 }
diff --git a/tests/vec4.rs b/tests/vec4.rs
index 8fc5097..3e7244b 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -504,6 +504,38 @@ macro_rules! impl_vec4_signed_tests {
     };
 }
 
+macro_rules! impl_vec4_eq_hash_tests {
+    ($t:ident, $new:ident) => {
+        #[test]
+        fn test_ve2_hash() {
+            use std::collections::hash_map::DefaultHasher;
+            use std::hash::Hash;
+            use std::hash::Hasher;
+
+            let a = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
+            let b = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
+            let c = $new(3 as $t, 2 as $t, 1 as $t, 4 as $t);
+
+            let mut hasher = DefaultHasher::new();
+            a.hash(&mut hasher);
+            let a_hashed = hasher.finish();
+
+            let mut hasher = DefaultHasher::new();
+            b.hash(&mut hasher);
+            let b_hashed = hasher.finish();
+
+            let mut hasher = DefaultHasher::new();
+            c.hash(&mut hasher);
+            let c_hashed = hasher.finish();
+
+            assert_eq!(a, b);
+            assert_eq!(a_hashed, b_hashed);
+            assert_ne!(a, c);
+            assert_ne!(a_hashed, c_hashed);
+        }
+    };
+}
+
 macro_rules! impl_vec4_float_tests {
     ($t:ident, $const_new:ident, $new:ident, $vec4:ident, $mask:ident) => {
         impl_vec4_signed_tests!($t, $const_new, $new, $vec4, $mask);
@@ -856,6 +888,7 @@ mod ivec4 {
     }
 
     impl_vec4_signed_tests!(i32, const_ivec4, ivec4, IVec4, BVec4);
+    impl_vec4_eq_hash_tests!(i32, ivec4);
 }
 
 mod uvec4 {
@@ -871,4 +904,5 @@ mod uvec4 {
     }
 
     impl_vec4_tests!(u32, const_uvec4, uvec4, UVec4, BVec4);
+    impl_vec4_eq_hash_tests!(u32, uvec4);
 }