Repository: bitshifter/glam-rs
Pull request #56 (2020-04-16 23:58:20)

Implements some common traits for Vec*Mask
Implements some of the traits asked in #13, those being `PartialEq`, `Eq`, `Hash`, `Debug` and `Display`


Patch:
diff --git a/src/f32/vec2_mask.rs b/src/f32/vec2_mask.rs
index b668c3a..808fdd5 100644
--- a/src/f32/vec2_mask.rs
+++ b/src/f32/vec2_mask.rs
@@ -1,10 +1,11 @@
 use super::Vec2;
+use core::fmt;
 use core::ops::*;
 
 /// A 2-dimensional vector mask.
 ///
 /// This type is typically created by comparison methods on `Vec2`.
-#[derive(Clone, Copy, Default)]
+#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
 #[repr(C)]
 pub struct Vec2Mask(u32, u32);
 
@@ -94,3 +95,15 @@ impl Not for Vec2Mask {
         Self(!self.0, !self.1)
     }
 }
+
+impl fmt::Debug for Vec2Mask {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Vec2Mask({:#x}, {:#x})", self.0, self.1)
+    }
+}
+
+impl fmt::Display for Vec2Mask {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{}, {}]", self.0 != 0, self.1 != 0)
+    }
+}
diff --git a/src/f32/vec3_mask.rs b/src/f32/vec3_mask.rs
index 59b6c39..052b8b8 100644
--- a/src/f32/vec3_mask.rs
+++ b/src/f32/vec3_mask.rs
@@ -1,10 +1,13 @@
 use super::Vec3;
+use core::fmt;
 use core::ops::*;
 
 #[cfg(all(vec3sse2, target_arch = "x86"))]
 use core::arch::x86::*;
 #[cfg(all(vec3sse2, target_arch = "x86_64"))]
 use core::arch::x86_64::*;
+#[cfg(vec3sse2)]
+use core::hash;
 
 /// A 3-dimensional vector mask.
 ///
@@ -17,7 +20,7 @@ pub struct Vec3Mask(pub(crate) __m128);
 
 /// A 3-dimensional vector mask.
 #[cfg(vec3f32)]
-#[derive(Clone, Copy, Default)]
+#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
 // if compiling with simd enabled assume alignment needs to match the simd type
 #[cfg_attr(vec3f32_align16, repr(align(16)))]
 #[repr(C)]
@@ -31,6 +34,28 @@ impl Default for Vec3Mask {
     }
 }
 
+#[cfg(vec3sse2)]
+impl PartialEq for Vec3Mask {
+    fn eq(&self, other: &Self) -> bool {
+        let self_arr: [u32; 3] = (*self).into();
+        let other_arr: [u32; 3] = (*other).into();
+
+        self_arr.eq(&other_arr)
+    }
+}
+
+#[cfg(vec3sse2)]
+impl Eq for Vec3Mask {}
+
+#[cfg(vec3sse2)]
+impl hash::Hash for Vec3Mask {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        let self_arr: [u32; 3] = (*self).into();
+
+        self_arr.hash(state);
+    }
+}
+
 impl Vec3Mask {
     /// Creates a new `Vec3Mask`.
     #[inline]
@@ -211,3 +236,48 @@ impl Not for Vec3Mask {
         }
     }
 }
+
+impl fmt::Debug for Vec3Mask {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        #[cfg(vec3sse2)]
+        {
+            let arr: [u32; 3] = (*self).into();
+            write!(f, "Vec3Mask({:#x}, {:#x}, {:#x})", arr[0], arr[1], arr[2])
+        }
+
+        #[cfg(vec3f32)]
+        {
+            write!(f, "Vec3Mask({:#x}, {:#x}, {:#x})", self.0, self.1, self.2)
+        }
+    }
+}
+
+impl fmt::Display for Vec3Mask {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        #[cfg(vec3sse2)]
+        {
+            let arr: [u32; 3] = (*self).into();
+
+            write!(f, "[{}, {}, {}]", arr[0] != 0, arr[1] != 0, arr[2] != 0)
+        }
+
+        #[cfg(vec3f32)]
+        {
+            write!(f, "[{}, {}, {}]", self.0 != 0, self.1 != 0, self.2 != 0)
+        }
+    }
+}
+
+impl From<Vec3Mask> for [u32; 3] {
+    fn from(mask: Vec3Mask) -> Self {
+        #[cfg(vec3sse2)]
+        {
+            unsafe { *(&mask as *const Vec3Mask as *const [u32; 3]) }
+        }
+
+        #[cfg(vec3f32)]
+        {
+            [mask.0, mask.1, mask.2]
+        }
+    }
+}
diff --git a/src/f32/vec4_mask.rs b/src/f32/vec4_mask.rs
index 3ee508d..ae0bedc 100644
--- a/src/f32/vec4_mask.rs
+++ b/src/f32/vec4_mask.rs
@@ -1,10 +1,13 @@
 use crate::Vec4;
+use core::fmt;
 use core::ops::*;
 
 #[cfg(all(vec4sse2, target_arch = "x86"))]
 use core::arch::x86::*;
 #[cfg(all(vec4sse2, target_arch = "x86_64"))]
 use core::arch::x86_64::*;
+#[cfg(vec4sse2)]
+use core::hash;
 
 /// A 4-dimensional vector mask.
 ///
@@ -16,7 +19,7 @@ use core::arch::x86_64::*;
 pub struct Vec4Mask(pub(crate) __m128);
 
 #[cfg(vec4f32)]
-#[derive(Clone, Copy, Default)]
+#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
 #[cfg_attr(vec4f32_align16, repr(align(16)))]
 #[repr(C)]
 pub struct Vec4Mask(u32, u32, u32, u32);
@@ -29,6 +32,28 @@ impl Default for Vec4Mask {
     }
 }
 
+#[cfg(vec4sse2)]
+impl PartialEq for Vec4Mask {
+    fn eq(&self, other: &Self) -> bool {
+        let self_arr: [u32; 4] = (*self).into();
+        let other_arr: [u32; 4] = (*other).into();
+
+        self_arr.eq(&other_arr)
+    }
+}
+
+#[cfg(vec4sse2)]
+impl Eq for Vec4Mask {}
+
+#[cfg(vec4sse2)]
+impl hash::Hash for Vec4Mask {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        let self_arr: [u32; 4] = (*self).into();
+
+        self_arr.hash(state);
+    }
+}
+
 impl Vec4Mask {
     /// Creates a new `Vec4Mask`.
     #[inline]
@@ -227,3 +252,70 @@ impl Not for Vec4Mask {
         }
     }
 }
+
+impl fmt::Debug for Vec4Mask {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        #[cfg(vec4sse2)]
+        {
+            let arr: [u32; 4] = (*self).into();
+            write!(
+                f,
+                "Vec4Mask({:#x}, {:#x}, {:#x}, {:#x})",
+                arr[0], arr[1], arr[2], arr[3]
+            )
+        }
+
+        #[cfg(vec4f32)]
+        {
+            write!(
+                f,
+                "Vec4Mask({:#x}, {:#x}, {:#x}, {:#x})",
+                self.0, self.1, self.2, self.3
+            )
+        }
+    }
+}
+
+impl fmt::Display for Vec4Mask {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        #[cfg(vec4sse2)]
+        {
+            let arr: [u32; 4] = (*self).into();
+
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                arr[0] != 0,
+                arr[1] != 0,
+                arr[2] != 0,
+                arr[3] != 0
+            )
+        }
+
+        #[cfg(vec4f32)]
+        {
+            write!(
+                f,
+                "[{}, {}, {}, {}]",
+                self.0 != 0,
+                self.1 != 0,
+                self.2 != 0,
+                self.3 != 0
+            )
+        }
+    }
+}
+
+impl From<Vec4Mask> for [u32; 4] {
+    fn from(mask: Vec4Mask) -> Self {
+        #[cfg(vec4sse2)]
+        {
+            unsafe { *(&mask as *const Vec4Mask as *const [u32; 4]) }
+        }
+
+        #[cfg(vec4f32)]
+        {
+            [mask.0, mask.1, mask.2, mask.3]
+        }
+    }
+}


Test patch:
diff --git a/tests/vec2.rs b/tests/vec2.rs
index 9e8daba..0b759f6 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -304,6 +304,14 @@ fn test_vec2mask_not() {
     assert_eq!((!Vec2Mask::new(true, true)).bitmask(), 0b00);
 }
 
+#[test]
+fn test_vec2mask_fmt() {
+    let a = Vec2Mask::new(true, false);
+
+    assert_eq!(format!("{:?}", a), "Vec2Mask(0xffffffff, 0x0)");
+    assert_eq!(format!("{}", a), "[true, false]");
+}
+
 #[test]
 fn test_vec2_sign() {
     assert_eq!(Vec2::zero().sign(), Vec2::one());
diff --git a/tests/vec3.rs b/tests/vec3.rs
index 4548aa9..946d85f 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -359,6 +359,74 @@ fn test_vec3mask_not() {
     assert_eq!((!Vec3Mask::new(false, true, false)).bitmask(), 0b101);
 }
 
+#[test]
+fn test_vec3mask_fmt() {
+    let a = Vec3Mask::new(true, false, false);
+
+    // debug fmt
+    #[cfg(all(
+        target_feature = "sse2",
+        not(feature = "packed-vec3"),
+        not(feature = "scalar-math")
+    ))]
+    assert_eq!(format!("{:?}", a), "Vec3Mask(0xffffffff, 0x0, 0x0)");
+
+    #[cfg(any(
+        not(target_feature = "sse2"),
+        feature = "packed-vec3",
+        feature = "scalar-math"
+    ))]
+    assert_eq!(format!("{:?}", a), "Vec3Mask(0xffffffff, 0x0, 0x0)");
+
+    // display fmt
+    #[cfg(all(
+        target_feature = "sse2",
+        not(feature = "packed-vec3"),
+        not(feature = "scalar-math")
+    ))]
+    assert_eq!(format!("{}", a), "[true, false, false]");
+
+    #[cfg(any(
+        not(target_feature = "sse2"),
+        feature = "packed-vec3",
+        feature = "scalar-math"
+    ))]
+    assert_eq!(format!("{}", a), "[true, false, false]");
+}
+
+#[test]
+fn test_vec3mask_eq() {
+    let a = Vec3Mask::new(true, false, true);
+    let b = Vec3Mask::new(true, false, true);
+    let c = Vec3Mask::new(false, true, true);
+
+    assert_eq!(a, b);
+    assert_eq!(b, a);
+    assert_ne!(a, c);
+    assert_ne!(b, c);
+}
+
+#[test]
+fn test_vec3mask_hash() {
+    use std::collections::hash_map::DefaultHasher;
+    use std::hash::Hash;
+    use std::hash::Hasher;
+
+    let a = Vec3Mask::new(true, false, true);
+    let b = Vec3Mask::new(true, false, true);
+
+    let mut a_hasher = DefaultHasher::new();
+    let mut b_hasher = DefaultHasher::new();
+
+    a.hash(&mut a_hasher);
+    let a_hashed = a_hasher.finish();
+    b.hash(&mut b_hasher);
+    let b_hashed = b_hasher.finish();
+
+    assert_eq!(a, b);
+    assert_eq!(a_hashed, b_hashed);
+}
+
 #[test]
 fn test_vec3_sign() {
     assert_eq!(Vec3::zero().sign(), Vec3::one());
diff --git a/tests/vec4.rs b/tests/vec4.rs
index 17fd783..c3aad61 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -407,6 +407,61 @@ fn test_vec4mask_not() {
     assert_eq!((!Vec4Mask::new(false, true, false, true)).bitmask(), 0b0101);
 }
 
+#[test]
+fn test_vec4mask_fmt() {
+    let a = Vec4Mask::new(true, false, true, false);
+
+    #[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
+    assert_eq!(format!("{}", a), "[true, false, true, false]");
+    #[cfg(all(target_feature = "sse2", not(feature = "scalar-math")))]
+    assert_eq!(
+        format!("{:?}", a),
+        "Vec4Mask(0xffffffff, 0x0, 0xffffffff, 0x0)"
+    );
+
+    #[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))]
+    assert_eq!(format!("{}", a), "[true, false, true, false]");
+    #[cfg(any(not(target_feature = "sse2"), feature = "scalar-math"))]
+    assert_eq!(
+        format!("{:?}", a),
+        "Vec4Mask(0xffffffff, 0x0, 0xffffffff, 0x0)"
+    );
+}
+
+#[test]
+fn test_vec4mask_eq() {
+    let a = Vec4Mask::new(true, false, true, false);
+    let b = Vec4Mask::new(true, false, true, false);
+    let c = Vec4Mask::new(false, true, true, false);
+
+    assert_eq!(a, b);
+    assert_eq!(b, a);
+    assert_ne!(a, c);
+    assert_ne!(b, c);
+}
+
+#[test]
+fn test_vec4mask_hash() {
+    use std::collections::hash_map::DefaultHasher;
+    use std::hash::Hash;
+    use std::hash::Hasher;
+
+    let a = Vec4Mask::new(true, false, true, false);
+    let b = Vec4Mask::new(true, false, true, false);
+
+    let mut a_hasher = DefaultHasher::new();
+    let mut b_hasher = DefaultHasher::new();
+
+    a.hash(&mut a_hasher);
+    let a_hashed = a_hasher.finish();
+    b.hash(&mut b_hasher);
+    let b_hashed = b_hasher.finish();
+
+    // if a == b then hash(a) == hash(b)
+    assert_eq!(a, b);
+    assert_eq!(a_hashed, b_hashed);
+}
+
 #[test]
 fn test_vec4_round() {
     assert_eq!(Vec4::new(1.35, 0.0, 0.0, 0.0).round().x(), 1.0);