Repository: bitshifter/glam-rs
Pull request #402 (2023-05-08 11:07:42)

Add `From` and `TryFrom` conversions.
Added these where there is a scalar equivalent in Rust.


Patch:
diff --git a/codegen/templates/vec.rs.tera b/codegen/templates/vec.rs.tera
index f647278..8cad9a9 100644
--- a/codegen/templates/vec.rs.tera
+++ b/codegen/templates/vec.rs.tera
@@ -35,6 +35,7 @@
         {% set vec2_t = "DVec2" %}
         {% set vec3_t = "DVec3" %}
         {% set vec4_t = "DVec4" %}
+        {% set from_types = ["Vec" ~ dim, "IVec" ~ dim, "UVec" ~ dim] %}
     {% endif %}
 {% elif scalar_t == "i32" %}
     {% set is_signed = true %}
@@ -43,6 +44,7 @@
     {% set vec2_t = "IVec2" %}
     {% set vec3_t = "IVec3" %}
     {% set vec4_t = "IVec4" %}
+    {% set try_from_types = ["UVec" ~ dim, "U64Vec" ~ dim, "I64Vec" ~ dim] %}
 {% elif scalar_t == "u32" %}
     {% set is_signed = false %}
     {% set is_float = false %}
@@ -50,6 +52,7 @@
     {% set vec2_t = "UVec2" %}
     {% set vec3_t = "UVec3" %}
     {% set vec4_t = "UVec4" %}
+    {% set try_from_types = ["IVec" ~ dim, "I64Vec" ~ dim, "U64Vec" ~ dim] %}
 {% elif scalar_t == "i64" %}
     {% set is_signed = true %}
     {% set is_float = false %}
@@ -57,13 +60,17 @@
     {% set vec2_t = "I64Vec2" %}
     {% set vec3_t = "I64Vec3" %}
     {% set vec4_t = "I64Vec4" %}
-{% else %}
+    {% set from_types = ["IVec" ~ dim] %}
+    {% set try_from_types = ["U64Vec" ~ dim] %}
+{% elif scalar_t == "u64" %}
     {% set is_signed = false %}
     {% set is_float = false %}
     {% set self_t = "U64Vec" ~ dim %}
     {% set vec2_t = "U64Vec2" %}
     {% set vec3_t = "U64Vec3" %}
     {% set vec4_t = "U64Vec4" %}
+    {% set from_types = ["UVec" ~ dim] %}
+    {% set try_from_types = ["I64Vec" ~ dim] %}
 {% endif %}
 
 {% if scalar_t == "f64" or scalar_t == "i64" or scalar_t == "u64" or dim == 4 %}
@@ -107,6 +114,16 @@ use crate::{
     {% if is_float %}
         {{ scalar_t }}::math,
     {% endif %}
+    {% if from_types %}
+        {% for ty in from_types %}
+            {{ ty }},
+        {% endfor %}
+    {% endif %}
+    {% if try_from_types %}
+        {% for ty in try_from_types %}
+            {{ ty }},
+        {% endfor %}
+    {% endif %}
 };
 
 #[cfg(not(target_arch = "spirv"))]
@@ -858,17 +875,16 @@ impl {{ self_t }} {
         {% endif %}
     }
 
+    {% if is_float %}
     /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
     #[inline]
     pub fn copysign(self, rhs: Self) -> Self {
-        {% if is_scalar and is_float %}
+        {% if is_scalar %}
             Self {
                 {% for c in components %}
                     {{ c }}: math::copysign(self.{{ c }}, rhs.{{ c }}),
                 {%- endfor %}
             }
-        {% elif is_scalar %}
-            Self::select(rhs.cmpge(Self::ZERO), self, -self)
         {% elif is_coresimd %}
             Self(self.0.copysign(rhs.0))
         {% elif is_sse2 %}
@@ -883,6 +899,7 @@ impl {{ self_t }} {
             }
         {% endif %}
     }
+    {% endif %}
 
     /// Returns a bitmask with the lowest {{ dim }} bits set to the sign bits from the elements of `self`.
     ///
@@ -2621,3 +2638,35 @@ impl DerefMut for {{ self_t }} {
     }
 }
 {% endif %}
+
+{% if from_types %}
+    {% for ty in from_types %}
+    impl From<{{ ty }}> for {{ self_t }} {
+        #[inline]
+        fn from(v: {{ ty }}) -> Self {
+            Self::new(
+                {% for c in components %}
+                    {{ scalar_t }}::from(v.{{ c }}),
+                {% endfor %}
+            )
+        }
+    }
+    {% endfor %}
+{% endif %}
+
+{% if try_from_types %}
+    {% for ty in try_from_types %}
+    impl TryFrom<{{ ty }}> for {{ self_t }} {
+        type Error = core::num::TryFromIntError;
+
+        #[inline]
+        fn try_from(v: {{ ty }}) -> Result<Self, Self::Error> {
+            Ok(Self::new(
+                {% for c in components %}
+                    {{ scalar_t }}::try_from(v.{{ c }})?,
+                {% endfor %}
+            ))
+        }
+    }
+    {% endfor %}
+{% endif %}
diff --git a/src/f64/dvec2.rs b/src/f64/dvec2.rs
index f243a70..87fd2ec 100644
--- a/src/f64/dvec2.rs
+++ b/src/f64/dvec2.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f64::math, BVec2, DVec3};
+use crate::{f64::math, BVec2, DVec3, IVec2, UVec2, Vec2};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -1066,3 +1066,24 @@ impl From<DVec2> for (f64, f64) {
         (v.x, v.y)
     }
 }
+
+impl From<Vec2> for DVec2 {
+    #[inline]
+    fn from(v: Vec2) -> Self {
+        Self::new(f64::from(v.x), f64::from(v.y))
+    }
+}
+
+impl From<IVec2> for DVec2 {
+    #[inline]
+    fn from(v: IVec2) -> Self {
+        Self::new(f64::from(v.x), f64::from(v.y))
+    }
+}
+
+impl From<UVec2> for DVec2 {
+    #[inline]
+    fn from(v: UVec2) -> Self {
+        Self::new(f64::from(v.x), f64::from(v.y))
+    }
+}
diff --git a/src/f64/dvec3.rs b/src/f64/dvec3.rs
index 9699f3c..cc54b62 100644
--- a/src/f64/dvec3.rs
+++ b/src/f64/dvec3.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f64::math, BVec3, DVec2, DVec4};
+use crate::{f64::math, BVec3, DVec2, DVec4, IVec3, UVec3, Vec3};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -1172,3 +1172,24 @@ impl From<(DVec2, f64)> for DVec3 {
         Self::new(v.x, v.y, z)
     }
 }
+
+impl From<Vec3> for DVec3 {
+    #[inline]
+    fn from(v: Vec3) -> Self {
+        Self::new(f64::from(v.x), f64::from(v.y), f64::from(v.z))
+    }
+}
+
+impl From<IVec3> for DVec3 {
+    #[inline]
+    fn from(v: IVec3) -> Self {
+        Self::new(f64::from(v.x), f64::from(v.y), f64::from(v.z))
+    }
+}
+
+impl From<UVec3> for DVec3 {
+    #[inline]
+    fn from(v: UVec3) -> Self {
+        Self::new(f64::from(v.x), f64::from(v.y), f64::from(v.z))
+    }
+}
diff --git a/src/f64/dvec4.rs b/src/f64/dvec4.rs
index 1b8f6ef..a5bdae5 100644
--- a/src/f64/dvec4.rs
+++ b/src/f64/dvec4.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{f64::math, BVec4, DVec2, DVec3};
+use crate::{f64::math, BVec4, DVec2, DVec3, IVec4, UVec4, Vec4};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -1196,3 +1196,39 @@ impl From<(DVec2, DVec2)> for DVec4 {
         Self::new(v.x, v.y, u.x, u.y)
     }
 }
+
+impl From<Vec4> for DVec4 {
+    #[inline]
+    fn from(v: Vec4) -> Self {
+        Self::new(
+            f64::from(v.x),
+            f64::from(v.y),
+            f64::from(v.z),
+            f64::from(v.w),
+        )
+    }
+}
+
+impl From<IVec4> for DVec4 {
+    #[inline]
+    fn from(v: IVec4) -> Self {
+        Self::new(
+            f64::from(v.x),
+            f64::from(v.y),
+            f64::from(v.z),
+            f64::from(v.w),
+        )
+    }
+}
+
+impl From<UVec4> for DVec4 {
+    #[inline]
+    fn from(v: UVec4) -> Self {
+        Self::new(
+            f64::from(v.x),
+            f64::from(v.y),
+            f64::from(v.z),
+            f64::from(v.w),
+        )
+    }
+}
diff --git a/src/i32/ivec2.rs b/src/i32/ivec2.rs
index 262a62d..a473c5b 100644
--- a/src/i32/ivec2.rs
+++ b/src/i32/ivec2.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, IVec3};
+use crate::{BVec2, I64Vec2, IVec3, U64Vec2, UVec2};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -258,12 +258,6 @@ impl IVec2 {
         }
     }
 
-    /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
-    #[inline]
-    pub fn copysign(self, rhs: Self) -> Self {
-        Self::select(rhs.cmpge(Self::ZERO), self, -self)
-    }
-
     /// Returns a bitmask with the lowest 2 bits set to the sign bits from the elements of `self`.
     ///
     /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
@@ -1031,3 +1025,30 @@ impl From<IVec2> for (i32, i32) {
         (v.x, v.y)
     }
 }
+
+impl TryFrom<UVec2> for IVec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i32::try_from(v.x)?, i32::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<U64Vec2> for IVec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i32::try_from(v.x)?, i32::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<I64Vec2> for IVec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i32::try_from(v.x)?, i32::try_from(v.y)?))
+    }
+}
diff --git a/src/i32/ivec3.rs b/src/i32/ivec3.rs
index 02d4b96..17fb97d 100644
--- a/src/i32/ivec3.rs
+++ b/src/i32/ivec3.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, IVec2, IVec4};
+use crate::{BVec3, I64Vec3, IVec2, IVec4, U64Vec3, UVec3};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -300,12 +300,6 @@ impl IVec3 {
         }
     }
 
-    /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
-    #[inline]
-    pub fn copysign(self, rhs: Self) -> Self {
-        Self::select(rhs.cmpge(Self::ZERO), self, -self)
-    }
-
     /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
     ///
     /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
@@ -1113,3 +1107,42 @@ impl From<(IVec2, i32)> for IVec3 {
         Self::new(v.x, v.y, z)
     }
 }
+
+impl TryFrom<UVec3> for IVec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i32::try_from(v.x)?,
+            i32::try_from(v.y)?,
+            i32::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<U64Vec3> for IVec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i32::try_from(v.x)?,
+            i32::try_from(v.y)?,
+            i32::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<I64Vec3> for IVec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i32::try_from(v.x)?,
+            i32::try_from(v.y)?,
+            i32::try_from(v.z)?,
+        ))
+    }
+}
diff --git a/src/i32/ivec4.rs b/src/i32/ivec4.rs
index 36bf5c6..345cb99 100644
--- a/src/i32/ivec4.rs
+++ b/src/i32/ivec4.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, IVec2, IVec3};
+use crate::{BVec4, I64Vec4, IVec2, IVec3, U64Vec4, UVec4};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -325,12 +325,6 @@ impl IVec4 {
         }
     }
 
-    /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
-    #[inline]
-    pub fn copysign(self, rhs: Self) -> Self {
-        Self::select(rhs.cmpge(Self::ZERO), self, -self)
-    }
-
     /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
     ///
     /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
@@ -1210,3 +1204,45 @@ impl From<(IVec2, IVec2)> for IVec4 {
         Self::new(v.x, v.y, u.x, u.y)
     }
 }
+
+impl TryFrom<UVec4> for IVec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: UVec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i32::try_from(v.x)?,
+            i32::try_from(v.y)?,
+            i32::try_from(v.z)?,
+            i32::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<U64Vec4> for IVec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i32::try_from(v.x)?,
+            i32::try_from(v.y)?,
+            i32::try_from(v.z)?,
+            i32::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<I64Vec4> for IVec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i32::try_from(v.x)?,
+            i32::try_from(v.y)?,
+            i32::try_from(v.z)?,
+            i32::try_from(v.w)?,
+        ))
+    }
+}
diff --git a/src/i64/i64vec2.rs b/src/i64/i64vec2.rs
index 21074f5..8dd3f42 100644
--- a/src/i64/i64vec2.rs
+++ b/src/i64/i64vec2.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, I64Vec3};
+use crate::{BVec2, I64Vec3, IVec2, U64Vec2};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -258,12 +258,6 @@ impl I64Vec2 {
         }
     }
 
-    /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
-    #[inline]
-    pub fn copysign(self, rhs: Self) -> Self {
-        Self::select(rhs.cmpge(Self::ZERO), self, -self)
-    }
-
     /// Returns a bitmask with the lowest 2 bits set to the sign bits from the elements of `self`.
     ///
     /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
@@ -1031,3 +1025,19 @@ impl From<I64Vec2> for (i64, i64) {
         (v.x, v.y)
     }
 }
+
+impl From<IVec2> for I64Vec2 {
+    #[inline]
+    fn from(v: IVec2) -> Self {
+        Self::new(i64::from(v.x), i64::from(v.y))
+    }
+}
+
+impl TryFrom<U64Vec2> for I64Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(i64::try_from(v.x)?, i64::try_from(v.y)?))
+    }
+}
diff --git a/src/i64/i64vec3.rs b/src/i64/i64vec3.rs
index 95bd8e1..e964e5d 100644
--- a/src/i64/i64vec3.rs
+++ b/src/i64/i64vec3.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, I64Vec2, I64Vec4};
+use crate::{BVec3, I64Vec2, I64Vec4, IVec3, U64Vec3};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -300,12 +300,6 @@ impl I64Vec3 {
         }
     }
 
-    /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
-    #[inline]
-    pub fn copysign(self, rhs: Self) -> Self {
-        Self::select(rhs.cmpge(Self::ZERO), self, -self)
-    }
-
     /// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
     ///
     /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
@@ -1113,3 +1107,23 @@ impl From<(I64Vec2, i64)> for I64Vec3 {
         Self::new(v.x, v.y, z)
     }
 }
+
+impl From<IVec3> for I64Vec3 {
+    #[inline]
+    fn from(v: IVec3) -> Self {
+        Self::new(i64::from(v.x), i64::from(v.y), i64::from(v.z))
+    }
+}
+
+impl TryFrom<U64Vec3> for I64Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i64::try_from(v.x)?,
+            i64::try_from(v.y)?,
+            i64::try_from(v.z)?,
+        ))
+    }
+}
diff --git a/src/i64/i64vec4.rs b/src/i64/i64vec4.rs
index 2ec1a67..ade7ade 100644
--- a/src/i64/i64vec4.rs
+++ b/src/i64/i64vec4.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, I64Vec2, I64Vec3};
+use crate::{BVec4, I64Vec2, I64Vec3, IVec4, U64Vec4};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -325,12 +325,6 @@ impl I64Vec4 {
         }
     }
 
-    /// Returns a vector with signs of `rhs` and the magnitudes of `self`.
-    #[inline]
-    pub fn copysign(self, rhs: Self) -> Self {
-        Self::select(rhs.cmpge(Self::ZERO), self, -self)
-    }
-
     /// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
     ///
     /// A negative element results in a `1` bit and a positive element in a `0` bit.  Element `x` goes
@@ -1210,3 +1204,29 @@ impl From<(I64Vec2, I64Vec2)> for I64Vec4 {
         Self::new(v.x, v.y, u.x, u.y)
     }
 }
+
+impl From<IVec4> for I64Vec4 {
+    #[inline]
+    fn from(v: IVec4) -> Self {
+        Self::new(
+            i64::from(v.x),
+            i64::from(v.y),
+            i64::from(v.z),
+            i64::from(v.w),
+        )
+    }
+}
+
+impl TryFrom<U64Vec4> for I64Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            i64::try_from(v.x)?,
+            i64::try_from(v.y)?,
+            i64::try_from(v.z)?,
+            i64::try_from(v.w)?,
+        ))
+    }
+}
diff --git a/src/u32/uvec2.rs b/src/u32/uvec2.rs
index bc24ae9..7d4d4d7 100644
--- a/src/u32/uvec2.rs
+++ b/src/u32/uvec2.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, UVec3};
+use crate::{BVec2, I64Vec2, IVec2, U64Vec2, UVec3};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -937,3 +937,30 @@ impl From<UVec2> for (u32, u32) {
         (v.x, v.y)
     }
 }
+
+impl TryFrom<IVec2> for UVec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u32::try_from(v.x)?, u32::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<I64Vec2> for UVec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u32::try_from(v.x)?, u32::try_from(v.y)?))
+    }
+}
+
+impl TryFrom<U64Vec2> for UVec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u32::try_from(v.x)?, u32::try_from(v.y)?))
+    }
+}
diff --git a/src/u32/uvec3.rs b/src/u32/uvec3.rs
index 009a3a9..4e99d31 100644
--- a/src/u32/uvec3.rs
+++ b/src/u32/uvec3.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, UVec2, UVec4};
+use crate::{BVec3, I64Vec3, IVec3, U64Vec3, UVec2, UVec4};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -1042,3 +1042,42 @@ impl From<(UVec2, u32)> for UVec3 {
         Self::new(v.x, v.y, z)
     }
 }
+
+impl TryFrom<IVec3> for UVec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u32::try_from(v.x)?,
+            u32::try_from(v.y)?,
+            u32::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<I64Vec3> for UVec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u32::try_from(v.x)?,
+            u32::try_from(v.y)?,
+            u32::try_from(v.z)?,
+        ))
+    }
+}
+
+impl TryFrom<U64Vec3> for UVec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u32::try_from(v.x)?,
+            u32::try_from(v.y)?,
+            u32::try_from(v.z)?,
+        ))
+    }
+}
diff --git a/src/u32/uvec4.rs b/src/u32/uvec4.rs
index 6657aca..d5be46e 100644
--- a/src/u32/uvec4.rs
+++ b/src/u32/uvec4.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, UVec2, UVec3};
+use crate::{BVec4, I64Vec4, IVec4, U64Vec4, UVec2, UVec3};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -1132,3 +1132,45 @@ impl From<(UVec2, UVec2)> for UVec4 {
         Self::new(v.x, v.y, u.x, u.y)
     }
 }
+
+impl TryFrom<IVec4> for UVec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: IVec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u32::try_from(v.x)?,
+            u32::try_from(v.y)?,
+            u32::try_from(v.z)?,
+            u32::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<I64Vec4> for UVec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u32::try_from(v.x)?,
+            u32::try_from(v.y)?,
+            u32::try_from(v.z)?,
+            u32::try_from(v.w)?,
+        ))
+    }
+}
+
+impl TryFrom<U64Vec4> for UVec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: U64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u32::try_from(v.x)?,
+            u32::try_from(v.y)?,
+            u32::try_from(v.z)?,
+            u32::try_from(v.w)?,
+        ))
+    }
+}
diff --git a/src/u64/u64vec2.rs b/src/u64/u64vec2.rs
index 4dfa9d7..7964a35 100644
--- a/src/u64/u64vec2.rs
+++ b/src/u64/u64vec2.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec2, U64Vec3};
+use crate::{BVec2, I64Vec2, U64Vec3, UVec2};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -937,3 +937,19 @@ impl From<U64Vec2> for (u64, u64) {
         (v.x, v.y)
     }
 }
+
+impl From<UVec2> for U64Vec2 {
+    #[inline]
+    fn from(v: UVec2) -> Self {
+        Self::new(u64::from(v.x), u64::from(v.y))
+    }
+}
+
+impl TryFrom<I64Vec2> for U64Vec2 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec2) -> Result<Self, Self::Error> {
+        Ok(Self::new(u64::try_from(v.x)?, u64::try_from(v.y)?))
+    }
+}
diff --git a/src/u64/u64vec3.rs b/src/u64/u64vec3.rs
index 7557e6e..bf36ae6 100644
--- a/src/u64/u64vec3.rs
+++ b/src/u64/u64vec3.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec3, U64Vec2, U64Vec4};
+use crate::{BVec3, I64Vec3, U64Vec2, U64Vec4, UVec3};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -1042,3 +1042,23 @@ impl From<(U64Vec2, u64)> for U64Vec3 {
         Self::new(v.x, v.y, z)
     }
 }
+
+impl From<UVec3> for U64Vec3 {
+    #[inline]
+    fn from(v: UVec3) -> Self {
+        Self::new(u64::from(v.x), u64::from(v.y), u64::from(v.z))
+    }
+}
+
+impl TryFrom<I64Vec3> for U64Vec3 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec3) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u64::try_from(v.x)?,
+            u64::try_from(v.y)?,
+            u64::try_from(v.z)?,
+        ))
+    }
+}
diff --git a/src/u64/u64vec4.rs b/src/u64/u64vec4.rs
index f13ceb3..c9645dc 100644
--- a/src/u64/u64vec4.rs
+++ b/src/u64/u64vec4.rs
@@ -1,6 +1,6 @@
 // Generated from vec.rs.tera template. Edit the template, not the generated file.
 
-use crate::{BVec4, U64Vec2, U64Vec3};
+use crate::{BVec4, I64Vec4, U64Vec2, U64Vec3, UVec4};
 
 #[cfg(not(target_arch = "spirv"))]
 use core::fmt;
@@ -1132,3 +1132,29 @@ impl From<(U64Vec2, U64Vec2)> for U64Vec4 {
         Self::new(v.x, v.y, u.x, u.y)
     }
 }
+
+impl From<UVec4> for U64Vec4 {
+    #[inline]
+    fn from(v: UVec4) -> Self {
+        Self::new(
+            u64::from(v.x),
+            u64::from(v.y),
+            u64::from(v.z),
+            u64::from(v.w),
+        )
+    }
+}
+
+impl TryFrom<I64Vec4> for U64Vec4 {
+    type Error = core::num::TryFromIntError;
+
+    #[inline]
+    fn try_from(v: I64Vec4) -> Result<Self, Self::Error> {
+        Ok(Self::new(
+            u64::try_from(v.x)?,
+            u64::try_from(v.y)?,
+            u64::try_from(v.z)?,
+            u64::try_from(v.w)?,
+        ))
+    }
+}


Test patch:
diff --git a/tests/vec2.rs b/tests/vec2.rs
index bdde85b..5fdefe4 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -100,6 +100,11 @@ macro_rules! impl_vec2_tests {
             let y = $new(0 as $t, 1 as $t);
             assert_eq!(1 as $t, x.dot(x));
             assert_eq!(0 as $t, x.dot(y));
+
+            assert_eq!(
+                $new(8 as $t, 8 as $t),
+                $new(1 as $t, 2 as $t).dot_into_vec($new(4 as $t, 2 as $t))
+            );
         });
 
         glam_test!(test_length_squared_unsigned, {
@@ -473,6 +478,22 @@ macro_rules! impl_vec2_signed_tests {
     ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => {
         impl_vec2_tests!($t, $new, $vec2, $vec3, $mask);
 
+        glam_test!(test_is_negative_bitmask, {
+            assert_eq!($vec2::ZERO.is_negative_bitmask(), 0b00);
+            assert_eq!($vec2::ONE.is_negative_bitmask(), 0b00);
+            assert_eq!((-$vec2::ONE).is_negative_bitmask(), 0b11);
+            assert_eq!($vec2::new(-1 as $t, 2 as $t).is_negative_bitmask(), 0b01);
+            assert_eq!($vec2::new(8 as $t, 3 as $t).is_negative_bitmask(), 0b00);
+            assert_eq!($vec2::new(3 as $t, -4 as $t).is_negative_bitmask(), 0b10);
+            assert_eq!($vec2::new(-2 as $t, -6 as $t).is_negative_bitmask(), 0b11);
+        });
+
+        glam_test!(test_abs, {
+            assert_eq!($vec2::ZERO.abs(), $vec2::ZERO);
+            assert_eq!($vec2::ONE.abs(), $vec2::ONE);
+            assert_eq!((-$vec2::ONE).abs(), $vec2::ONE);
+        });
+
         glam_test!(test_dot_signed, {
             let x = $new(1 as $t, 0 as $t);
             let y = $new(0 as $t, 1 as $t);
@@ -516,6 +537,18 @@ macro_rules! impl_vec2_signed_tests {
     };
 }
 
+macro_rules! impl_vec2_signed_integer_tests {
+    ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident) => {
+        impl_vec2_signed_tests!($t, $new, $vec2, $vec3, $mask);
+
+        glam_test!(test_signum, {
+            assert_eq!($vec3::ZERO.signum(), $vec3::ZERO);
+            assert_eq!($vec3::ONE.signum(), $vec3::ONE);
+            assert_eq!((-$vec3::ONE).signum(), -$vec3::ONE);
+        });
+    };
+}
+
 macro_rules! impl_vec2_eq_hash_tests {
     ($t:ident, $new:ident) => {
         glam_test!(test_ve2_hash, {
@@ -571,7 +604,6 @@ macro_rules! impl_vec2_float_tests {
             assert_eq!(13.0, (-5.0 * x).distance(12.0 * y));
             assert_eq!(x, (2.0 * x).normalize());
             assert_eq!(1.0 * 3.0 + 2.0 * 4.0, $new(1.0, 2.0).dot($new(3.0, 4.0)));
-            assert_eq!($new(8.0, 8.0), $new(1.0, 2.0).dot_into_vec($new(4.0, 2.0)));
             assert_eq!(
                 (2.0 as $t * 2.0 + 3.0 * 3.0).sqrt(),
                 $new(2.0, 3.0).length()
@@ -652,21 +684,15 @@ macro_rules! impl_vec2_float_tests {
             assert!($vec2::splat(NAN).copysign(-$vec2::ONE).is_nan_mask().all());
         });
 
-        glam_test!(test_is_negative_bitmask, {
+        glam_test!(test_float_is_negative_bitmask, {
             assert_eq!($vec2::ZERO.is_negative_bitmask(), 0b00);
             assert_eq!((-$vec2::ZERO).is_negative_bitmask(), 0b11);
             assert_eq!($vec2::ONE.is_negative_bitmask(), 0b00);
             assert_eq!((-$vec2::ONE).is_negative_bitmask(), 0b11);
-            assert_eq!($vec2::new(-0.1, 0.2).is_negative_bitmask(), 0b01);
-            assert_eq!($vec2::new(0.8, 0.3).is_negative_bitmask(), 0b00);
-            assert_eq!($vec2::new(0.3, -0.4).is_negative_bitmask(), 0b10);
-            assert_eq!($vec2::new(-0.2, -0.6).is_negative_bitmask(), 0b11);
-        });
-
-        glam_test!(test_abs, {
-            assert_eq!($vec2::ZERO.abs(), $vec2::ZERO);
-            assert_eq!($vec2::ONE.abs(), $vec2::ONE);
-            assert_eq!((-$vec2::ONE).abs(), $vec2::ONE);
+            assert_eq!($vec2::new(-1.0, 2.0).is_negative_bitmask(), 0b01);
+            assert_eq!($vec2::new(8.0, 3.0).is_negative_bitmask(), 0b00);
+            assert_eq!($vec2::new(3.0, -4.0).is_negative_bitmask(), 0b10);
+            assert_eq!($vec2::new(-2.0, -6.0).is_negative_bitmask(), 0b11);
         });
 
         glam_test!(test_round, {
@@ -864,6 +890,10 @@ macro_rules! impl_vec2_scalar_shift_op_tests {
             use glam::$vec2;
             impl_vec2_scalar_shift_op_test!($vec2, $t_min, $t_max, 0i32, 2);
         }
+        mod shift_by_i64 {
+            use glam::$vec2;
+            impl_vec2_scalar_shift_op_test!($vec2, $t_min, $t_max, 0i64, 2);
+        }
         mod shift_by_u8 {
             use glam::$vec2;
             impl_vec2_scalar_shift_op_test!($vec2, $t_min, $t_max, 0u8, 2);
@@ -876,6 +906,10 @@ macro_rules! impl_vec2_scalar_shift_op_tests {
             use glam::$vec2;
             impl_vec2_scalar_shift_op_test!($vec2, $t_min, $t_max, 0u32, 2);
         }
+        mod shift_by_u64 {
+            use glam::$vec2;
+            impl_vec2_scalar_shift_op_test!($vec2, $t_min, $t_max, 0u64, 2);
+        }
     };
 }
 
@@ -1017,7 +1051,7 @@ mod vec2 {
 }
 
 mod dvec2 {
-    use glam::{dvec2, BVec2, DVec2, DVec3};
+    use glam::{dvec2, BVec2, DVec2, DVec3, IVec2, UVec2, Vec2};
 
     glam_test!(test_align, {
         use core::mem;
@@ -1030,11 +1064,17 @@ mod dvec2 {
         assert_eq!(1, mem::align_of::<BVec2>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(DVec2::new(1.0, 2.0), DVec2::from(Vec2::new(1.0, 2.0)));
+        assert_eq!(DVec2::new(1.0, 2.0), DVec2::from(IVec2::new(1, 2)));
+        assert_eq!(DVec2::new(1.0, 2.0), DVec2::from(UVec2::new(1, 2)));
+    });
+
     impl_vec2_float_tests!(f64, dvec2, DVec2, DVec3, BVec2);
 }
 
 mod ivec2 {
-    use glam::{ivec2, BVec2, IVec2, IVec3, UVec2};
+    use glam::{ivec2, BVec2, I64Vec2, IVec2, IVec3, U64Vec2, UVec2};
 
     glam_test!(test_align, {
         use core::mem;
@@ -1047,7 +1087,27 @@ mod ivec2 {
         assert_eq!(1, mem::align_of::<BVec2>());
     });
 
-    impl_vec2_signed_tests!(i32, ivec2, IVec2, IVec3, BVec2);
+    glam_test!(test_try_from, {
+        assert_eq!(IVec2::new(1, 2), IVec2::try_from(UVec2::new(1, 2)).unwrap());
+        assert!(IVec2::try_from(UVec2::new(u32::MAX, 2)).is_err());
+        assert!(IVec2::try_from(UVec2::new(1, u32::MAX)).is_err());
+
+        assert_eq!(
+            IVec2::new(1, 2),
+            IVec2::try_from(I64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(IVec2::try_from(I64Vec2::new(i64::MAX, 2)).is_err());
+        assert!(IVec2::try_from(I64Vec2::new(1, i64::MAX)).is_err());
+
+        assert_eq!(
+            IVec2::new(1, 2),
+            IVec2::try_from(U64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(IVec2::try_from(U64Vec2::new(u64::MAX, 2)).is_err());
+        assert!(IVec2::try_from(U64Vec2::new(1, u64::MAX)).is_err());
+    });
+
+    impl_vec2_signed_integer_tests!(i32, ivec2, IVec2, IVec3, BVec2);
     impl_vec2_eq_hash_tests!(i32, ivec2);
 
     impl_vec2_scalar_shift_op_tests!(IVec2, -2, 2);
@@ -1058,7 +1118,7 @@ mod ivec2 {
 }
 
 mod uvec2 {
-    use glam::{uvec2, BVec2, IVec2, UVec2, UVec3};
+    use glam::{uvec2, BVec2, I64Vec2, IVec2, U64Vec2, UVec2, UVec3};
 
     glam_test!(test_align, {
         use core::mem;
@@ -1071,6 +1131,29 @@ mod uvec2 {
         assert_eq!(1, mem::align_of::<BVec2>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(UVec2::new(1, 2), UVec2::try_from(IVec2::new(1, 2)).unwrap());
+        assert!(UVec2::try_from(IVec2::new(-1, 2)).is_err());
+        assert!(UVec2::try_from(IVec2::new(1, -2)).is_err());
+
+        assert_eq!(
+            UVec2::new(1, 2),
+            UVec2::try_from(I64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(UVec2::try_from(I64Vec2::new(-1, 2)).is_err());
+        assert!(UVec2::try_from(I64Vec2::new(1, -2)).is_err());
+
+        assert!(UVec2::try_from(I64Vec2::new(i64::MAX, 2)).is_err());
+        assert!(UVec2::try_from(I64Vec2::new(1, i64::MAX)).is_err());
+
+        assert_eq!(
+            UVec2::new(1, 2),
+            UVec2::try_from(U64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(UVec2::try_from(U64Vec2::new(u64::MAX, 2)).is_err());
+        assert!(UVec2::try_from(U64Vec2::new(1, u64::MAX)).is_err());
+    });
+
     impl_vec2_tests!(u32, uvec2, UVec2, UVec3, BVec2);
     impl_vec2_eq_hash_tests!(u32, uvec2);
 
@@ -1082,7 +1165,7 @@ mod uvec2 {
 }
 
 mod i64vec2 {
-    use glam::{i64vec2, BVec2, I64Vec2, I64Vec3, IVec2, UVec2};
+    use glam::{i64vec2, BVec2, I64Vec2, I64Vec3, IVec2, U64Vec2, UVec2};
 
     glam_test!(test_align, {
         use core::mem;
@@ -1095,7 +1178,21 @@ mod i64vec2 {
         assert_eq!(1, mem::align_of::<BVec2>());
     });
 
-    impl_vec2_signed_tests!(i64, i64vec2, I64Vec2, I64Vec3, BVec2);
+    glam_test!(test_try_from, {
+        assert_eq!(
+            I64Vec2::new(1, 2),
+            I64Vec2::try_from(IVec2::new(1, 2)).unwrap()
+        );
+
+        assert_eq!(
+            I64Vec2::new(1, 2),
+            I64Vec2::try_from(U64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(I64Vec2::try_from(U64Vec2::new(u64::MAX, 2)).is_err());
+        assert!(I64Vec2::try_from(U64Vec2::new(1, u64::MAX)).is_err());
+    });
+
+    impl_vec2_signed_integer_tests!(i64, i64vec2, I64Vec2, I64Vec3, BVec2);
     impl_vec2_eq_hash_tests!(i64, i64vec2);
 
     impl_vec2_scalar_shift_op_tests!(I64Vec2, -2, 2);
@@ -1106,7 +1203,7 @@ mod i64vec2 {
 }
 
 mod u64vec2 {
-    use glam::{u64vec2, BVec2, IVec2, U64Vec2, U64Vec3, UVec2};
+    use glam::{u64vec2, BVec2, I64Vec2, IVec2, U64Vec2, U64Vec3, UVec2};
 
     glam_test!(test_align, {
         use core::mem;
@@ -1119,6 +1216,20 @@ mod u64vec2 {
         assert_eq!(1, mem::align_of::<BVec2>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(
+            U64Vec2::new(1, 2),
+            U64Vec2::try_from(UVec2::new(1, 2)).unwrap()
+        );
+
+        assert_eq!(
+            U64Vec2::new(1, 2),
+            U64Vec2::try_from(I64Vec2::new(1, 2)).unwrap()
+        );
+        assert!(U64Vec2::try_from(I64Vec2::new(-1, 2)).is_err());
+        assert!(U64Vec2::try_from(I64Vec2::new(1, -2)).is_err());
+    });
+
     impl_vec2_tests!(u64, u64vec2, U64Vec2, U64Vec3, BVec2);
     impl_vec2_eq_hash_tests!(u64, u64vec2);
 
diff --git a/tests/vec3.rs b/tests/vec3.rs
index 250ea97..562a27e 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -108,6 +108,11 @@ macro_rules! impl_vec3_tests {
             let y = $new(0 as $t, 1 as $t, 0 as $t);
             assert_eq!(1 as $t, x.dot(x));
             assert_eq!(0 as $t, x.dot(y));
+
+            assert_eq!(
+                $new(14 as $t, 14 as $t, 14 as $t),
+                $new(0 as $t, 4 as $t, 6 as $t).dot_into_vec($new(3 as $t, 2 as $t, 1 as $t))
+            );
         });
 
         glam_test!(test_length_squared_unsigned, {
@@ -537,6 +542,38 @@ macro_rules! impl_vec3_signed_tests {
             );
         });
 
+        glam_test!(test_is_negative_bitmask, {
+            assert_eq!($vec3::ZERO.is_negative_bitmask(), 0b000);
+            assert_eq!($vec3::ONE.is_negative_bitmask(), 0b000);
+            assert_eq!((-$vec3::ONE).is_negative_bitmask(), 0b111);
+            assert_eq!(
+                $vec3::new(-1 as $t, 2 as $t, 3 as $t).is_negative_bitmask(),
+                0b001
+            );
+            assert_eq!(
+                $vec3::new(8 as $t, 3 as $t, 1 as $t).is_negative_bitmask(),
+                0b000
+            );
+            assert_eq!(
+                $vec3::new(1 as $t, 5 as $t, -3 as $t).is_negative_bitmask(),
+                0b100
+            );
+            assert_eq!(
+                $vec3::new(3 as $t, -4 as $t, 1 as $t).is_negative_bitmask(),
+                0b010
+            );
+            assert_eq!(
+                $vec3::new(-2 as $t, 6 as $t, -5 as $t).is_negative_bitmask(),
+                0b101
+            );
+        });
+
+        glam_test!(test_abs, {
+            assert_eq!($vec3::ZERO.abs(), $vec3::ZERO);
+            assert_eq!($vec3::ONE.abs(), $vec3::ONE);
+            assert_eq!((-$vec3::ONE).abs(), $vec3::ONE);
+        });
+
         glam_test!(test_dot_signed, {
             let x = $new(1 as $t, 0 as $t, 0 as $t);
             let y = $new(0 as $t, 1 as $t, 0 as $t);
@@ -561,6 +598,18 @@ macro_rules! impl_vec3_signed_tests {
     };
 }
 
+macro_rules! impl_vec3_signed_integer_tests {
+    ($t:ident, $new:ident, $vec3:ident, $mask:ident) => {
+        impl_vec3_signed_tests!($t, $new, $vec3, $mask);
+
+        glam_test!(test_signum, {
+            assert_eq!($vec3::ZERO.signum(), $vec3::ZERO);
+            assert_eq!($vec3::ONE.signum(), $vec3::ONE);
+            assert_eq!((-$vec3::ONE).signum(), -$vec3::ONE);
+        });
+    };
+}
+
 macro_rules! impl_vec3_eq_hash_tests {
     ($t:ident, $new:ident) => {
         glam_test!(test_vec3_hash, {
@@ -623,10 +672,6 @@ macro_rules! impl_vec3_float_tests {
                 1.0 * 4.0 + 2.0 * 5.0 + 3.0 * 6.0,
                 $new(1.0, 2.0, 3.0).dot($new(4.0, 5.0, 6.0))
             );
-            assert_eq!(
-                $new(14.0, 14.0, 14.0),
-                $new(0.0, 4.0, 6.0).dot_into_vec($new(3.0, 2.0, 1.0))
-            );
             assert_eq!(
                 (2.0 as $t * 2.0 + 3.0 * 3.0 + 4.0 * 4.0).sqrt(),
                 $new(2.0, 3.0, 4.0).length()
@@ -713,22 +758,16 @@ macro_rules! impl_vec3_float_tests {
             assert!($vec3::splat(NAN).copysign(-$vec3::ONE).is_nan_mask().all());
         });
 
-        glam_test!(test_is_negative_bitmask, {
+        glam_test!(test_float_is_negative_bitmask, {
             assert_eq!($vec3::ZERO.is_negative_bitmask(), 0b000);
             assert_eq!((-$vec3::ZERO).is_negative_bitmask(), 0b111);
             assert_eq!($vec3::ONE.is_negative_bitmask(), 0b000);
             assert_eq!((-$vec3::ONE).is_negative_bitmask(), 0b111);
-            assert_eq!($vec3::new(-0.1, 0.2, 0.3).is_negative_bitmask(), 0b001);
-            assert_eq!($vec3::new(0.8, 0.3, 0.1).is_negative_bitmask(), 0b000);
-            assert_eq!($vec3::new(0.1, 0.5, -0.3).is_negative_bitmask(), 0b100);
-            assert_eq!($vec3::new(0.3, -0.4, 0.1).is_negative_bitmask(), 0b010);
-            assert_eq!($vec3::new(-0.2, 0.6, -0.5).is_negative_bitmask(), 0b101);
-        });
-
-        glam_test!(test_abs, {
-            assert_eq!($vec3::ZERO.abs(), $vec3::ZERO);
-            assert_eq!($vec3::ONE.abs(), $vec3::ONE);
-            assert_eq!((-$vec3::ONE).abs(), $vec3::ONE);
+            assert_eq!($vec3::new(-1.0, 2.0, 3.0).is_negative_bitmask(), 0b001);
+            assert_eq!($vec3::new(8.0, 3.0, 1.0).is_negative_bitmask(), 0b000);
+            assert_eq!($vec3::new(1.0, 5.0, -3.0).is_negative_bitmask(), 0b100);
+            assert_eq!($vec3::new(3.0, -4.0, 1.0).is_negative_bitmask(), 0b010);
+            assert_eq!($vec3::new(-2.0, 6.0, -5.0).is_negative_bitmask(), 0b101);
         });
 
         glam_test!(test_round, {
@@ -944,6 +983,10 @@ macro_rules! impl_vec3_scalar_shift_op_tests {
             use glam::$vec3;
             impl_vec3_scalar_shift_op_test!($vec3, $t_min, $t_max, 0i32, 2);
         }
+        mod shift_by_i64 {
+            use glam::$vec3;
+            impl_vec3_scalar_shift_op_test!($vec3, $t_min, $t_max, 0i64, 2);
+        }
         mod shift_by_u8 {
             use glam::$vec3;
             impl_vec3_scalar_shift_op_test!($vec3, $t_min, $t_max, 0u8, 2);
@@ -956,6 +999,10 @@ macro_rules! impl_vec3_scalar_shift_op_tests {
             use glam::$vec3;
             impl_vec3_scalar_shift_op_test!($vec3, $t_min, $t_max, 0u32, 2);
         }
+        mod shift_by_u64 {
+            use glam::$vec3;
+            impl_vec3_scalar_shift_op_test!($vec3, $t_min, $t_max, 0u64, 2);
+        }
     };
 }
 
@@ -1248,7 +1295,7 @@ mod vec3a {
 }
 
 mod dvec3 {
-    use glam::{dvec3, BVec3, DVec3};
+    use glam::{dvec3, BVec3, DVec3, IVec3, UVec3, Vec3};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1258,11 +1305,20 @@ mod dvec3 {
         assert_eq!(1, mem::align_of::<BVec3>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(
+            DVec3::new(1.0, 2.0, 3.0),
+            DVec3::from(Vec3::new(1.0, 2.0, 3.0))
+        );
+        assert_eq!(DVec3::new(1.0, 2.0, 3.0), DVec3::from(IVec3::new(1, 2, 3)));
+        assert_eq!(DVec3::new(1.0, 2.0, 3.0), DVec3::from(UVec3::new(1, 2, 3)));
+    });
+
     impl_vec3_float_tests!(f64, dvec3, DVec3, BVec3);
 }
 
 mod ivec3 {
-    use glam::{ivec3, BVec3, IVec3, UVec3};
+    use glam::{ivec3, BVec3, I64Vec3, IVec3, U64Vec3, UVec3};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1272,7 +1328,33 @@ mod ivec3 {
         assert_eq!(1, mem::align_of::<BVec3>());
     });
 
-    impl_vec3_signed_tests!(i32, ivec3, IVec3, BVec3);
+    glam_test!(test_try_from, {
+        assert_eq!(
+            IVec3::new(1, 2, 3),
+            IVec3::try_from(UVec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(IVec3::try_from(UVec3::new(u32::MAX, 2, 3)).is_err());
+        assert!(IVec3::try_from(UVec3::new(1, u32::MAX, 3)).is_err());
+        assert!(IVec3::try_from(UVec3::new(1, 2, u32::MAX)).is_err());
+
+        assert_eq!(
+            IVec3::new(1, 2, 3),
+            IVec3::try_from(I64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(IVec3::try_from(I64Vec3::new(i64::MAX, 2, 3)).is_err());
+        assert!(IVec3::try_from(I64Vec3::new(1, i64::MAX, 3)).is_err());
+        assert!(IVec3::try_from(I64Vec3::new(1, 2, i64::MAX)).is_err());
+
+        assert_eq!(
+            IVec3::new(1, 2, 3),
+            IVec3::try_from(U64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(IVec3::try_from(U64Vec3::new(u64::MAX, 2, 3)).is_err());
+        assert!(IVec3::try_from(U64Vec3::new(1, u64::MAX, 3)).is_err());
+        assert!(IVec3::try_from(U64Vec3::new(1, 2, u64::MAX)).is_err());
+    });
+
+    impl_vec3_signed_integer_tests!(i32, ivec3, IVec3, BVec3);
     impl_vec3_eq_hash_tests!(i32, ivec3);
 
     impl_vec3_scalar_shift_op_tests!(IVec3, -2, 2);
@@ -1283,7 +1365,7 @@ mod ivec3 {
 }
 
 mod uvec3 {
-    use glam::{uvec3, BVec3, IVec3, UVec3};
+    use glam::{uvec3, BVec3, I64Vec3, IVec3, U64Vec3, UVec3};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1293,6 +1375,36 @@ mod uvec3 {
         assert_eq!(1, mem::align_of::<BVec3>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(
+            UVec3::new(1, 2, 3),
+            UVec3::try_from(IVec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(UVec3::try_from(IVec3::new(-1, 2, 3)).is_err());
+        assert!(UVec3::try_from(IVec3::new(1, -2, 3)).is_err());
+        assert!(UVec3::try_from(IVec3::new(1, 2, -3)).is_err());
+
+        assert_eq!(
+            UVec3::new(1, 2, 3),
+            UVec3::try_from(I64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(UVec3::try_from(I64Vec3::new(-1, 2, 3)).is_err());
+        assert!(UVec3::try_from(I64Vec3::new(1, -2, 3)).is_err());
+        assert!(UVec3::try_from(I64Vec3::new(1, 2, -3)).is_err());
+
+        assert!(UVec3::try_from(I64Vec3::new(i64::MAX, 2, 3)).is_err());
+        assert!(UVec3::try_from(I64Vec3::new(1, i64::MAX, 3)).is_err());
+        assert!(UVec3::try_from(I64Vec3::new(1, 2, i64::MAX)).is_err());
+
+        assert_eq!(
+            UVec3::new(1, 2, 3),
+            UVec3::try_from(U64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(UVec3::try_from(U64Vec3::new(u64::MAX, 2, 3)).is_err());
+        assert!(UVec3::try_from(U64Vec3::new(1, u64::MAX, 3)).is_err());
+        assert!(UVec3::try_from(U64Vec3::new(1, 2, u64::MAX)).is_err());
+    });
+
     impl_vec3_tests!(u32, uvec3, UVec3, BVec3);
     impl_vec3_eq_hash_tests!(u32, uvec3);
 
@@ -1304,7 +1416,7 @@ mod uvec3 {
 }
 
 mod i64vec3 {
-    use glam::{i64vec3, BVec3, I64Vec3, IVec3, UVec3};
+    use glam::{i64vec3, BVec3, I64Vec3, IVec3, U64Vec3, UVec3};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1314,7 +1426,22 @@ mod i64vec3 {
         assert_eq!(1, mem::align_of::<BVec3>());
     });
 
-    impl_vec3_signed_tests!(i64, i64vec3, I64Vec3, BVec3);
+    glam_test!(test_try_from, {
+        assert_eq!(
+            I64Vec3::new(1, 2, 3),
+            I64Vec3::try_from(IVec3::new(1, 2, 3)).unwrap()
+        );
+
+        assert_eq!(
+            I64Vec3::new(1, 2, 3),
+            I64Vec3::try_from(U64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(I64Vec3::try_from(U64Vec3::new(u64::MAX, 2, 3)).is_err());
+        assert!(I64Vec3::try_from(U64Vec3::new(1, u64::MAX, 3)).is_err());
+        assert!(I64Vec3::try_from(U64Vec3::new(1, 2, u64::MAX)).is_err());
+    });
+
+    impl_vec3_signed_integer_tests!(i64, i64vec3, I64Vec3, BVec3);
     impl_vec3_eq_hash_tests!(i64, i64vec3);
 
     impl_vec3_scalar_shift_op_tests!(I64Vec3, -2, 2);
@@ -1325,7 +1452,7 @@ mod i64vec3 {
 }
 
 mod u64vec3 {
-    use glam::{u64vec3, BVec3, IVec3, U64Vec3, UVec3};
+    use glam::{u64vec3, BVec3, I64Vec3, IVec3, U64Vec3, UVec3};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1335,6 +1462,21 @@ mod u64vec3 {
         assert_eq!(1, mem::align_of::<BVec3>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(
+            U64Vec3::new(1, 2, 3),
+            U64Vec3::try_from(UVec3::new(1, 2, 3)).unwrap()
+        );
+
+        assert_eq!(
+            U64Vec3::new(1, 2, 3),
+            U64Vec3::try_from(I64Vec3::new(1, 2, 3)).unwrap()
+        );
+        assert!(U64Vec3::try_from(I64Vec3::new(-1, 2, 3)).is_err());
+        assert!(U64Vec3::try_from(I64Vec3::new(1, -2, 3)).is_err());
+        assert!(U64Vec3::try_from(I64Vec3::new(1, 2, -3)).is_err());
+    });
+
     impl_vec3_tests!(u64, u64vec3, U64Vec3, BVec3);
     impl_vec3_eq_hash_tests!(u64, u64vec3);
 
diff --git a/tests/vec4.rs b/tests/vec4.rs
index 59d1fb9..030181f 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -146,6 +146,12 @@ macro_rules! impl_vec4_tests {
             assert_eq!(0 as $t, x.dot(y));
             assert_eq!(0 as $t, y.dot(z));
             assert_eq!(0 as $t, z.dot(w));
+
+            assert_eq!(
+                $new(28 as $t, 28 as $t, 28 as $t, 28 as $t),
+                $new(0 as $t, 5 as $t, 3 as $t, 6 as $t)
+                    .dot_into_vec($new(7 as $t, 2 as $t, 4 as $t, 1 as $t))
+            );
         });
 
         glam_test!(test_length_squared_unsigned, {
@@ -609,13 +615,41 @@ macro_rules! impl_vec4_signed_tests {
             let a = $new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
             assert_eq!((-1 as $t, -2 as $t, -3 as $t, -4 as $t), (-a).into());
             assert_eq!(
-                $new(-0.0 as $t, -0.0 as $t, -0.0 as $t, -0.0 as $t),
-                -$new(0.0 as $t, 0.0 as $t, 0.0 as $t, 0.0 as $t)
+                $new(-0 as $t, -0 as $t, -0 as $t, -0 as $t),
+                -$new(0 as $t, 0 as $t, 0 as $t, 0 as $t)
+            );
+            assert_eq!(
+                $new(0 as $t, -0 as $t, -0 as $t, -0 as $t),
+                -$new(-0 as $t, 0 as $t, 0 as $t, 0 as $t)
+            );
+        });
+
+        glam_test!(test_is_negative_bitmask, {
+            assert_eq!($vec4::ZERO.is_negative_bitmask(), 0b0000);
+            assert_eq!($vec4::ONE.is_negative_bitmask(), 0b0000);
+            assert_eq!((-$vec4::ONE).is_negative_bitmask(), 0b1111);
+            assert_eq!(
+                $vec4::new(-1 as $t, 2 as $t, 3 as $t, -4 as $t).is_negative_bitmask(),
+                0b1001
             );
             assert_eq!(
-                $new(0.0 as $t, -0.0 as $t, -0.0 as $t, -0.0 as $t),
-                -$new(-0.0 as $t, 0.0 as $t, 0.0 as $t, 0.0 as $t)
+                $vec4::new(1 as $t, 5 as $t, -3 as $t, 7 as $t).is_negative_bitmask(),
+                0b0100
             );
+            assert_eq!(
+                $vec4::new(3 as $t, -4 as $t, 1 as $t, 6 as $t).is_negative_bitmask(),
+                0b0010
+            );
+            assert_eq!(
+                $vec4::new(2 as $t, -6 as $t, 5 as $t, -3 as $t).is_negative_bitmask(),
+                0b1010
+            );
+        });
+
+        glam_test!(test_abs, {
+            assert_eq!($vec4::ZERO.abs(), $vec4::ZERO);
+            assert_eq!($vec4::ONE.abs(), $vec4::ONE);
+            assert_eq!((-$vec4::ONE).abs(), $vec4::ONE);
         });
 
         glam_test!(test_dot_signed, {
@@ -648,6 +682,18 @@ macro_rules! impl_vec4_signed_tests {
     };
 }
 
+macro_rules! impl_vec4_signed_integer_tests {
+    ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident) => {
+        impl_vec4_signed_tests!($t, $new, $vec4, $vec3, $vec2, $mask);
+
+        glam_test!(test_signum, {
+            assert_eq!($vec4::ZERO.signum(), $vec4::ZERO);
+            assert_eq!($vec4::ONE.signum(), $vec4::ONE);
+            assert_eq!((-$vec4::ONE).signum(), -$vec4::ONE);
+        });
+    };
+}
+
 macro_rules! impl_vec4_eq_hash_tests {
     ($t:ident, $new:ident) => {
         glam_test!(test_ve2_hash, {
@@ -710,10 +756,6 @@ macro_rules! impl_vec4_float_tests {
                 1.0 * 5.0 + 2.0 * 6.0 + 3.0 * 7.0 + 4.0 * 8.0,
                 $new(1.0, 2.0, 3.0, 4.0).dot($new(5.0, 6.0, 7.0, 8.0))
             );
-            assert_eq!(
-                $new(28.0, 28.0, 28.0, 28.0),
-                $new(0.0, 5.0, 3.0, 6.0).dot_into_vec($new(7.0, 2.0, 4.0, 1.0))
-            );
             assert_eq!(
                 (2.0 as $t * 2.0 + 3.0 * 3.0 + 4.0 * 4.0 + 5.0 * 5.0).sqrt(),
                 $new(2.0, 3.0, 4.0, 5.0).length()
@@ -804,39 +846,33 @@ macro_rules! impl_vec4_float_tests {
             assert!($vec4::splat(NAN).copysign(-$vec4::ONE).is_nan_mask().all());
         });
 
-        glam_test!(test_is_negative_bitmask, {
+        glam_test!(test_float_is_negative_bitmask, {
             assert_eq!($vec4::ZERO.is_negative_bitmask(), 0b0000);
             assert_eq!((-$vec4::ZERO).is_negative_bitmask(), 0b1111);
             assert_eq!($vec4::ONE.is_negative_bitmask(), 0b0000);
             assert_eq!((-$vec4::ONE).is_negative_bitmask(), 0b1111);
             assert_eq!(
-                $vec4::new(-0.1, 0.2, 0.3, -0.4).is_negative_bitmask(),
+                $vec4::new(-1.0, 2.0, 3.0, -4.0).is_negative_bitmask(),
                 0b1001
             );
             assert_eq!(
-                $vec4::new(0.8, 0.3, 0.1, -0.0).is_negative_bitmask(),
+                $vec4::new(8.0, 3.0, 1.0, -0.0).is_negative_bitmask(),
                 0b1000
             );
             assert_eq!(
-                $vec4::new(0.1, 0.5, -0.3, 0.7).is_negative_bitmask(),
+                $vec4::new(1.0, 5.0, -3.0, 7.0).is_negative_bitmask(),
                 0b0100
             );
             assert_eq!(
-                $vec4::new(0.3, -0.4, 0.1, 0.6).is_negative_bitmask(),
+                $vec4::new(3.0, -4.0, 1.0, 6.0).is_negative_bitmask(),
                 0b0010
             );
             assert_eq!(
-                $vec4::new(0.2, -0.6, 0.5, -0.3).is_negative_bitmask(),
+                $vec4::new(2.0, -6.0, 5.0, -3.0).is_negative_bitmask(),
                 0b1010
             );
         });
 
-        glam_test!(test_abs, {
-            assert_eq!($vec4::ZERO.abs(), $vec4::ZERO);
-            assert_eq!($vec4::ONE.abs(), $vec4::ONE);
-            assert_eq!((-$vec4::ONE).abs(), $vec4::ONE);
-        });
-
         glam_test!(test_round, {
             assert_eq!($vec4::new(1.35, 0.0, 0.0, 0.0).round().x, 1.0);
             assert_eq!($vec4::new(0.0, 1.5, 0.0, 0.0).round().y, 2.0);
@@ -1029,6 +1065,10 @@ macro_rules! impl_vec4_scalar_shift_op_tests {
             use glam::$vec4;
             impl_vec4_scalar_shift_op_test!($vec4, $t_min, $t_max, 0i32, 2);
         }
+        mod shift_by_i64 {
+            use glam::$vec4;
+            impl_vec4_scalar_shift_op_test!($vec4, $t_min, $t_max, 0i64, 2);
+        }
         mod shift_by_u8 {
             use glam::$vec4;
             impl_vec4_scalar_shift_op_test!($vec4, $t_min, $t_max, 0u8, 2);
@@ -1041,6 +1081,10 @@ macro_rules! impl_vec4_scalar_shift_op_tests {
             use glam::$vec4;
             impl_vec4_scalar_shift_op_test!($vec4, $t_min, $t_max, 0u32, 2);
         }
+        mod shift_by_u64 {
+            use glam::$vec4;
+            impl_vec4_scalar_shift_op_test!($vec4, $t_min, $t_max, 0u64, 2);
+        }
     };
 }
 
@@ -1361,7 +1405,7 @@ mod vec4 {
 }
 
 mod dvec4 {
-    use glam::{dvec4, BVec4, DVec2, DVec3, DVec4};
+    use glam::{dvec4, BVec4, DVec2, DVec3, DVec4, IVec4, UVec4, Vec4};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1374,11 +1418,26 @@ mod dvec4 {
         assert_eq!(1, mem::align_of::<BVec4>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(
+            DVec4::new(1.0, 2.0, 3.0, 4.0),
+            DVec4::from(Vec4::new(1.0, 2.0, 3.0, 4.0))
+        );
+        assert_eq!(
+            DVec4::new(1.0, 2.0, 3.0, 4.0),
+            DVec4::from(IVec4::new(1, 2, 3, 4))
+        );
+        assert_eq!(
+            DVec4::new(1.0, 2.0, 3.0, 4.0),
+            DVec4::from(UVec4::new(1, 2, 3, 4))
+        );
+    });
+
     impl_vec4_float_tests!(f64, dvec4, DVec4, DVec3, DVec2, BVec4);
 }
 
 mod ivec4 {
-    use glam::{ivec4, BVec4, IVec2, IVec3, IVec4, UVec4};
+    use glam::{ivec4, BVec4, I64Vec4, IVec2, IVec3, IVec4, U64Vec4, UVec4};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1391,7 +1450,36 @@ mod ivec4 {
         assert_eq!(1, mem::align_of::<BVec4>());
     });
 
-    impl_vec4_signed_tests!(i32, ivec4, IVec4, IVec3, IVec2, BVec4);
+    glam_test!(test_try_from, {
+        assert_eq!(
+            IVec4::new(1, 2, 3, 4),
+            IVec4::try_from(UVec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(IVec4::try_from(UVec4::new(u32::MAX, 2, 3, 4)).is_err());
+        assert!(IVec4::try_from(UVec4::new(1, u32::MAX, 3, 4)).is_err());
+        assert!(IVec4::try_from(UVec4::new(1, 2, u32::MAX, 4)).is_err());
+        assert!(IVec4::try_from(UVec4::new(1, 2, 3, u32::MAX)).is_err());
+
+        assert_eq!(
+            IVec4::new(1, 2, 3, 4),
+            IVec4::try_from(I64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(IVec4::try_from(I64Vec4::new(i64::MAX, 2, 3, 4)).is_err());
+        assert!(IVec4::try_from(I64Vec4::new(1, i64::MAX, 3, 4)).is_err());
+        assert!(IVec4::try_from(I64Vec4::new(1, 2, i64::MAX, 4)).is_err());
+        assert!(IVec4::try_from(I64Vec4::new(1, 2, 3, i64::MAX)).is_err());
+
+        assert_eq!(
+            IVec4::new(1, 2, 3, 4),
+            IVec4::try_from(U64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(IVec4::try_from(U64Vec4::new(u64::MAX, 2, 3, 4)).is_err());
+        assert!(IVec4::try_from(U64Vec4::new(1, u64::MAX, 3, 4)).is_err());
+        assert!(IVec4::try_from(U64Vec4::new(1, 2, u64::MAX, 4)).is_err());
+        assert!(IVec4::try_from(U64Vec4::new(1, 2, 3, u64::MAX)).is_err());
+    });
+
+    impl_vec4_signed_integer_tests!(i32, ivec4, IVec4, IVec3, IVec2, BVec4);
     impl_vec4_eq_hash_tests!(i32, ivec4);
 
     impl_vec4_scalar_shift_op_tests!(IVec4, -2, 2);
@@ -1402,7 +1490,7 @@ mod ivec4 {
 }
 
 mod uvec4 {
-    use glam::{uvec4, BVec4, IVec4, UVec2, UVec3, UVec4};
+    use glam::{uvec4, BVec4, I64Vec4, IVec4, U64Vec4, UVec2, UVec3, UVec4};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1415,6 +1503,40 @@ mod uvec4 {
         assert_eq!(1, mem::align_of::<BVec4>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(
+            UVec4::new(1, 2, 3, 4),
+            UVec4::try_from(IVec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(UVec4::try_from(IVec4::new(-1, 2, 3, 4)).is_err());
+        assert!(UVec4::try_from(IVec4::new(1, -2, 3, 4)).is_err());
+        assert!(UVec4::try_from(IVec4::new(1, 2, -3, 4)).is_err());
+        assert!(UVec4::try_from(IVec4::new(1, 2, 3, -4)).is_err());
+
+        assert_eq!(
+            UVec4::new(1, 2, 3, 4),
+            UVec4::try_from(I64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(UVec4::try_from(I64Vec4::new(-1, 2, 3, 4)).is_err());
+        assert!(UVec4::try_from(I64Vec4::new(1, -2, 3, 4)).is_err());
+        assert!(UVec4::try_from(I64Vec4::new(1, 2, -3, 4)).is_err());
+        assert!(UVec4::try_from(I64Vec4::new(1, 2, 3, -4)).is_err());
+
+        assert!(UVec4::try_from(I64Vec4::new(i64::MAX, 2, 3, 4)).is_err());
+        assert!(UVec4::try_from(I64Vec4::new(1, i64::MAX, 3, 4)).is_err());
+        assert!(UVec4::try_from(I64Vec4::new(1, 2, i64::MAX, 4)).is_err());
+        assert!(UVec4::try_from(I64Vec4::new(1, 2, 3, i64::MAX)).is_err());
+
+        assert_eq!(
+            UVec4::new(1, 2, 3, 4),
+            UVec4::try_from(U64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(UVec4::try_from(U64Vec4::new(u64::MAX, 2, 3, 4)).is_err());
+        assert!(UVec4::try_from(U64Vec4::new(1, u64::MAX, 3, 4)).is_err());
+        assert!(UVec4::try_from(U64Vec4::new(1, 2, u64::MAX, 4)).is_err());
+        assert!(UVec4::try_from(U64Vec4::new(1, 2, 3, u64::MAX)).is_err());
+    });
+
     impl_vec4_tests!(u32, uvec4, UVec4, UVec3, UVec2, BVec4);
     impl_vec4_eq_hash_tests!(u32, uvec4);
 
@@ -1426,7 +1548,7 @@ mod uvec4 {
 }
 
 mod i64vec4 {
-    use glam::{i64vec4, BVec4, I64Vec2, I64Vec3, I64Vec4, IVec4, UVec4};
+    use glam::{i64vec4, BVec4, I64Vec2, I64Vec3, I64Vec4, IVec4, U64Vec4, UVec4};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1439,7 +1561,23 @@ mod i64vec4 {
         assert_eq!(1, mem::align_of::<BVec4>());
     });
 
-    impl_vec4_signed_tests!(i64, i64vec4, I64Vec4, I64Vec3, I64Vec2, BVec4);
+    glam_test!(test_try_from, {
+        assert_eq!(
+            I64Vec4::new(1, 2, 3, 4),
+            I64Vec4::try_from(IVec4::new(1, 2, 3, 4)).unwrap()
+        );
+
+        assert_eq!(
+            I64Vec4::new(1, 2, 3, 4),
+            I64Vec4::try_from(U64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(I64Vec4::try_from(U64Vec4::new(u64::MAX, 2, 3, 4)).is_err());
+        assert!(I64Vec4::try_from(U64Vec4::new(1, u64::MAX, 3, 4)).is_err());
+        assert!(I64Vec4::try_from(U64Vec4::new(1, 2, u64::MAX, 4)).is_err());
+        assert!(I64Vec4::try_from(U64Vec4::new(1, 2, 3, u64::MAX)).is_err());
+    });
+
+    impl_vec4_signed_integer_tests!(i64, i64vec4, I64Vec4, I64Vec3, I64Vec2, BVec4);
     impl_vec4_eq_hash_tests!(i64, i64vec4);
 
     impl_vec4_scalar_shift_op_tests!(I64Vec4, -2, 2);
@@ -1450,7 +1588,7 @@ mod i64vec4 {
 }
 
 mod u64vec4 {
-    use glam::{u64vec4, BVec4, IVec4, U64Vec2, U64Vec3, U64Vec4, UVec4};
+    use glam::{u64vec4, BVec4, I64Vec4, IVec4, U64Vec2, U64Vec3, U64Vec4, UVec4};
 
     glam_test!(test_align, {
         use std::mem;
@@ -1463,6 +1601,22 @@ mod u64vec4 {
         assert_eq!(1, mem::align_of::<BVec4>());
     });
 
+    glam_test!(test_try_from, {
+        assert_eq!(
+            U64Vec4::new(1, 2, 3, 4),
+            U64Vec4::try_from(UVec4::new(1, 2, 3, 4)).unwrap()
+        );
+
+        assert_eq!(
+            U64Vec4::new(1, 2, 3, 4),
+            U64Vec4::try_from(I64Vec4::new(1, 2, 3, 4)).unwrap()
+        );
+        assert!(U64Vec4::try_from(I64Vec4::new(-1, 2, 3, 4)).is_err());
+        assert!(U64Vec4::try_from(I64Vec4::new(1, -2, 3, 4)).is_err());
+        assert!(U64Vec4::try_from(I64Vec4::new(1, 2, -3, 4)).is_err());
+        assert!(U64Vec4::try_from(I64Vec4::new(1, 2, 3, -4)).is_err());
+    });
+
     impl_vec4_tests!(u64, u64vec4, U64Vec4, U64Vec3, U64Vec2, BVec4);
     impl_vec4_eq_hash_tests!(u64, u64vec4);