Repository: bitshifter/glam-rs
Pull request #547 (2024-08-08 07:34:26)

Generic mapping function for vectors
Hi! Sorry I didn't make a discussion about this first, didn't read the guidelines until I already wrote this up, so figured I might as well post the PR.

This adds a generic mapping function that acts on all of the elements of a vector. Adding it to matrices as well might be useful, but my use cases for this has always just been vectors so far. I'm happy to add it to matrices if you think that'd be good for consistency's sake.

The use case, as an example, I had recently was taking any vector element in a normal below some `EPSILON` and setting it to 0.0, since the collision normal that was generated was a little bit finnicky. I don't see that use case alone as very useful in the library, but allowing per-element operations definitely is imo.

Aceeri: https://github.com/bevyengine/bevy/pull/14656/files#diff-0e640ab491c46a3af5c0e6c590467e40376348c3ccb7f4f69612765c96370fc4R381

Another example pointed out by @Jondolf
Aceeri: > I was expecting someone to suggest this eventually :)
> 
> One change that I think would make sense is add it for all vector types, not just floating point vectors, I don't think there's any reason not to? This should just be a case of moving the function in codegen to a common area, it would also require tests (which again is mostly a case of moving them to a common location and casting the inputs to the scalar type in the test).

Oop ya that makes sense, I had thought this already did this but didn't check.
Aceeri: Aaaa not sure what happened here
Aceeri: Whoops, did a silly

Patch:
diff --git a/codegen/templates/vec.rs.tera b/codegen/templates/vec.rs.tera
index 2373f84..e8408ff 100644
--- a/codegen/templates/vec.rs.tera
+++ b/codegen/templates/vec.rs.tera
@@ -411,6 +411,20 @@ impl {{ self_t }} {
         {% endif %}
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn({{ scalar_t }}) -> {{ scalar_t }},
+    {
+        Self::new(
+            {% for c in components %}
+                f(self.{{ c }}),
+            {%- endfor %}
+        )
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/euler.rs b/src/euler.rs
index 7a90d40..fba11a7 100644
--- a/src/euler.rs
+++ b/src/euler.rs
@@ -78,6 +78,13 @@ pub enum EulerRot {
     XZXEx,
 }
 
+impl Default for EulerRot {
+    /// Default `YXZ` as yaw (y-axis), pitch (x-axis), roll (z-axis).
+    fn default() -> Self {
+        Self::YXZ
+    }
+}
+
 pub(crate) trait ToEuler {
     type Scalar;
     fn to_euler_angles(self, order: EulerRot) -> (Self::Scalar, Self::Scalar, Self::Scalar);
diff --git a/src/f32/coresimd/vec3a.rs b/src/f32/coresimd/vec3a.rs
index 61c9862..8d280e0 100644
--- a/src/f32/coresimd/vec3a.rs
+++ b/src/f32/coresimd/vec3a.rs
@@ -90,6 +90,16 @@ impl Vec3A {
         Self(Simd::from_array([v; 4]))
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/coresimd/vec4.rs b/src/f32/coresimd/vec4.rs
index c19b4bb..47d0bc6 100644
--- a/src/f32/coresimd/vec4.rs
+++ b/src/f32/coresimd/vec4.rs
@@ -92,6 +92,16 @@ impl Vec4 {
         Self(Simd::from_array([v; 4]))
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/neon/vec3a.rs b/src/f32/neon/vec3a.rs
index 510c974..5b80cb3 100644
--- a/src/f32/neon/vec3a.rs
+++ b/src/f32/neon/vec3a.rs
@@ -95,6 +95,16 @@ impl Vec3A {
         unsafe { UnionCast { a: [v; 4] }.v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/neon/vec4.rs b/src/f32/neon/vec4.rs
index f0e6b40..1c81ea1 100644
--- a/src/f32/neon/vec4.rs
+++ b/src/f32/neon/vec4.rs
@@ -97,6 +97,16 @@ impl Vec4 {
         unsafe { UnionCast { a: [v; 4] }.v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/scalar/vec3a.rs b/src/f32/scalar/vec3a.rs
index 68bbb5c..50a788a 100644
--- a/src/f32/scalar/vec3a.rs
+++ b/src/f32/scalar/vec3a.rs
@@ -93,6 +93,16 @@ impl Vec3A {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/scalar/vec4.rs b/src/f32/scalar/vec4.rs
index 53f0dd8..1afdabd 100644
--- a/src/f32/scalar/vec4.rs
+++ b/src/f32/scalar/vec4.rs
@@ -111,6 +111,16 @@ impl Vec4 {
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/sse2/vec3a.rs b/src/f32/sse2/vec3a.rs
index 5c0be25..0f92f52 100644
--- a/src/f32/sse2/vec3a.rs
+++ b/src/f32/sse2/vec3a.rs
@@ -98,6 +98,16 @@ impl Vec3A {
         unsafe { UnionCast { a: [v; 4] }.v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/sse2/vec4.rs b/src/f32/sse2/vec4.rs
index d65a9ac..c773f68 100644
--- a/src/f32/sse2/vec4.rs
+++ b/src/f32/sse2/vec4.rs
@@ -100,6 +100,16 @@ impl Vec4 {
         unsafe { UnionCast { a: [v; 4] }.v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/vec2.rs b/src/f32/vec2.rs
index 38c566a..241774a 100644
--- a/src/f32/vec2.rs
+++ b/src/f32/vec2.rs
@@ -78,6 +78,16 @@ impl Vec2 {
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/vec3.rs b/src/f32/vec3.rs
index a0981cc..b5a5a4f 100644
--- a/src/f32/vec3.rs
+++ b/src/f32/vec3.rs
@@ -84,6 +84,16 @@ impl Vec3 {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/wasm32/vec3a.rs b/src/f32/wasm32/vec3a.rs
index ccb949b..8d682dd 100644
--- a/src/f32/wasm32/vec3a.rs
+++ b/src/f32/wasm32/vec3a.rs
@@ -89,6 +89,16 @@ impl Vec3A {
         Self(f32x4(v, v, v, v))
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f32/wasm32/vec4.rs b/src/f32/wasm32/vec4.rs
index 18cfe54..d552616 100644
--- a/src/f32/wasm32/vec4.rs
+++ b/src/f32/wasm32/vec4.rs
@@ -91,6 +91,16 @@ impl Vec4 {
         Self(f32x4(v, v, v, v))
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f32) -> f32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f64/dvec2.rs b/src/f64/dvec2.rs
index 92c9f5a..61aa26d 100644
--- a/src/f64/dvec2.rs
+++ b/src/f64/dvec2.rs
@@ -78,6 +78,16 @@ impl DVec2 {
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f64) -> f64,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f64/dvec3.rs b/src/f64/dvec3.rs
index 3c59185..5e4b483 100644
--- a/src/f64/dvec3.rs
+++ b/src/f64/dvec3.rs
@@ -84,6 +84,16 @@ impl DVec3 {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f64) -> f64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/f64/dvec4.rs b/src/f64/dvec4.rs
index 7663fad..314a48e 100644
--- a/src/f64/dvec4.rs
+++ b/src/f64/dvec4.rs
@@ -102,6 +102,16 @@ impl DVec4 {
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(f64) -> f64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i16/i16vec2.rs b/src/i16/i16vec2.rs
index 3f81c11..3dc20b7 100644
--- a/src/i16/i16vec2.rs
+++ b/src/i16/i16vec2.rs
@@ -70,6 +70,16 @@ impl I16Vec2 {
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i16) -> i16,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i16/i16vec3.rs b/src/i16/i16vec3.rs
index 538cfaa..028e1eb 100644
--- a/src/i16/i16vec3.rs
+++ b/src/i16/i16vec3.rs
@@ -76,6 +76,16 @@ impl I16Vec3 {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i16) -> i16,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i16/i16vec4.rs b/src/i16/i16vec4.rs
index f9b875f..3531109 100644
--- a/src/i16/i16vec4.rs
+++ b/src/i16/i16vec4.rs
@@ -94,6 +94,16 @@ impl I16Vec4 {
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i16) -> i16,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i32/ivec2.rs b/src/i32/ivec2.rs
index a13b9be..fbbcae3 100644
--- a/src/i32/ivec2.rs
+++ b/src/i32/ivec2.rs
@@ -70,6 +70,16 @@ impl IVec2 {
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i32) -> i32,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i32/ivec3.rs b/src/i32/ivec3.rs
index 777f4b7..a361b32 100644
--- a/src/i32/ivec3.rs
+++ b/src/i32/ivec3.rs
@@ -76,6 +76,16 @@ impl IVec3 {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i32) -> i32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i32/ivec4.rs b/src/i32/ivec4.rs
index 4b4b557..78c3047 100644
--- a/src/i32/ivec4.rs
+++ b/src/i32/ivec4.rs
@@ -94,6 +94,16 @@ impl IVec4 {
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i32) -> i32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i64/i64vec2.rs b/src/i64/i64vec2.rs
index f49091b..7bffc21 100644
--- a/src/i64/i64vec2.rs
+++ b/src/i64/i64vec2.rs
@@ -70,6 +70,16 @@ impl I64Vec2 {
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i64) -> i64,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i64/i64vec3.rs b/src/i64/i64vec3.rs
index 9412a32..edade91 100644
--- a/src/i64/i64vec3.rs
+++ b/src/i64/i64vec3.rs
@@ -76,6 +76,16 @@ impl I64Vec3 {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i64) -> i64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/i64/i64vec4.rs b/src/i64/i64vec4.rs
index ef9ab1e..5b42af0 100644
--- a/src/i64/i64vec4.rs
+++ b/src/i64/i64vec4.rs
@@ -94,6 +94,16 @@ impl I64Vec4 {
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(i64) -> i64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u16/u16vec2.rs b/src/u16/u16vec2.rs
index 4a01ea7..5b4cb6a 100644
--- a/src/u16/u16vec2.rs
+++ b/src/u16/u16vec2.rs
@@ -61,6 +61,16 @@ impl U16Vec2 {
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u16) -> u16,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u16/u16vec3.rs b/src/u16/u16vec3.rs
index 2d26d9b..b560a49 100644
--- a/src/u16/u16vec3.rs
+++ b/src/u16/u16vec3.rs
@@ -64,6 +64,16 @@ impl U16Vec3 {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u16) -> u16,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u16/u16vec4.rs b/src/u16/u16vec4.rs
index d5dfba0..982466c 100644
--- a/src/u16/u16vec4.rs
+++ b/src/u16/u16vec4.rs
@@ -79,6 +79,16 @@ impl U16Vec4 {
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u16) -> u16,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u32/uvec2.rs b/src/u32/uvec2.rs
index 7189117..40cc663 100644
--- a/src/u32/uvec2.rs
+++ b/src/u32/uvec2.rs
@@ -61,6 +61,16 @@ impl UVec2 {
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u32) -> u32,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u32/uvec3.rs b/src/u32/uvec3.rs
index 0804645..96f7501 100644
--- a/src/u32/uvec3.rs
+++ b/src/u32/uvec3.rs
@@ -64,6 +64,16 @@ impl UVec3 {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u32) -> u32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u32/uvec4.rs b/src/u32/uvec4.rs
index bb2147e..b5bd298 100644
--- a/src/u32/uvec4.rs
+++ b/src/u32/uvec4.rs
@@ -79,6 +79,16 @@ impl UVec4 {
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u32) -> u32,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u64/u64vec2.rs b/src/u64/u64vec2.rs
index 5c7b853..ff99a5a 100644
--- a/src/u64/u64vec2.rs
+++ b/src/u64/u64vec2.rs
@@ -61,6 +61,16 @@ impl U64Vec2 {
         Self { x: v, y: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u64) -> u64,
+    {
+        Self::new(f(self.x), f(self.y))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u64/u64vec3.rs b/src/u64/u64vec3.rs
index 59d32f3..1a65b87 100644
--- a/src/u64/u64vec3.rs
+++ b/src/u64/u64vec3.rs
@@ -64,6 +64,16 @@ impl U64Vec3 {
         Self { x: v, y: v, z: v }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u64) -> u64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///
diff --git a/src/u64/u64vec4.rs b/src/u64/u64vec4.rs
index 66b8b3b..2038d28 100644
--- a/src/u64/u64vec4.rs
+++ b/src/u64/u64vec4.rs
@@ -79,6 +79,16 @@ impl U64Vec4 {
         }
     }
 
+    /// Returns a vector containing each element of `self` modified by a mapping function `f`.
+    #[inline]
+    #[must_use]
+    pub fn map<F>(self, f: F) -> Self
+    where
+        F: Fn(u64) -> u64,
+    {
+        Self::new(f(self.x), f(self.y), f(self.z), f(self.w))
+    }
+
     /// Creates a vector from the elements in `if_true` and `if_false`, selecting which to use
     /// for each element of `self`.
     ///


Test patch:
diff --git a/tests/euler.rs b/tests/euler.rs
index c89eff6..3890f25 100644
--- a/tests/euler.rs
+++ b/tests/euler.rs
@@ -252,6 +252,11 @@ mod euler {
         };
     }
 
+    #[test]
+    fn test_euler_default() {
+        assert_eq!(EulerRot::YXZ, EulerRot::default());
+    }
+
     mod quat {
         impl_quat_euler_test!(Quat, f32);
     }
diff --git a/tests/vec2.rs b/tests/vec2.rs
index b574768..f16b86f 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -84,6 +84,12 @@ macro_rules! impl_vec2_tests {
             assert_eq!($vec2::ONE, v);
         });
 
+        glam_test!(test_map, {
+            let v = $vec2::new(1 as $t, 2 as $t);
+            assert_eq!(v.map(|n| n + 3 as $t), v + $vec2::splat(3 as $t));
+            assert_eq!(v.map(|_| 0 as $t), $vec2::ZERO);
+        });
+
         glam_test!(test_with, {
             assert_eq!($vec2::X, $vec2::ZERO.with_x(1 as $t));
             assert_eq!($vec2::Y, $vec2::ZERO.with_y(1 as $t));
diff --git a/tests/vec3.rs b/tests/vec3.rs
index 82877ef..62ce25a 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -110,6 +110,12 @@ macro_rules! impl_vec3_tests {
             assert_eq!($vec3::ONE, v);
         });
 
+        glam_test!(test_map, {
+            let v = $vec3::new(1 as $t, 2 as $t, 3 as $t);
+            assert_eq!(v.map(|n| n + 3 as $t), v + $vec3::splat(3 as $t));
+            assert_eq!(v.map(|_| 0 as $t), $vec3::ZERO);
+        });
+
         glam_test!(test_with, {
             assert_eq!($vec3::X, $vec3::ZERO.with_x(1 as $t));
             assert_eq!($vec3::Y, $vec3::ZERO.with_y(1 as $t));
diff --git a/tests/vec4.rs b/tests/vec4.rs
index 47599e1..4d36d95 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -152,6 +152,12 @@ macro_rules! impl_vec4_tests {
             assert_eq!($vec4::ONE, v);
         });
 
+        glam_test!(test_map, {
+            let v = $vec4::new(1 as $t, 2 as $t, 3 as $t, 4 as $t);
+            assert_eq!(v.map(|n| n + 3 as $t), v + $vec4::splat(3 as $t));
+            assert_eq!(v.map(|_| 0 as $t), $vec4::ZERO);
+        });
+
         glam_test!(test_with, {
             assert_eq!($vec4::X, $vec4::ZERO.with_x(1 as $t));
             assert_eq!($vec4::Y, $vec4::ZERO.with_y(1 as $t));