Repository: bitshifter/glam-rs
Pull request #596 (2025-01-18 04:35:01)

Add checked_* elementwise arithmetic operations for {I,U}Vec{2,3,4}
For integer vectors, it's often useful to check if an operation would overflow. This helps with writing more robust code without having to do checks with `if` statements. Since we already have `wrapping_` and `saturating_` from Rust standard library, I figured having `checked_` would be welcome as well.

The test code is sadly very repetitive, as it's not generated from a template. Hopefully I got it all copy-pasted correctly!


Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..0d04990
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,29 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Describe the bug**
+
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+
+Can you provide some code that demonstrate the bug
+
+**Expected behavior**
+
+A clear and concise description of what you expected to happen.
+
+**System information (please complete the following information):**
+
+ - OS: [e.g. Linux]
+ - Architecture [e.g. x86_64]
+
+**Additional context**
+
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..ef26939
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+  - name: Ask a question
+    url: https://github.com/bitshifter/glam-rs/discussions
+    about: Please ask and answer questions here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..9c2051c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,26 @@
+---
+name: Feature request
+about: Propose a new feature
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**What problem does this solve or what need does it fill?**
+
+A clear and concise description of what the problem is.
+
+**Describe the solution you'd like**
+
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+
+What is your use case for this feature?
+
+How do you intend to use it?
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..8387f35
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,31 @@
+# Objective
+
+- Describe the objective or issue this PR addresses.
+- If you're fixing a specific issue, say "Fixes #X".
+
+## Solution
+
+- Describe the solution used to achieve the objective above.
+
+## Code generation
+
+- Most code in glam is generated by an offline tool.
+- Are you modify generated code?
+- Have you modified the templates and run the code generator?
+
+See https://github.com/bitshifter/glam-rs/blob/main/codegen/README.md for details.
+
+## Testing and linting
+
+- Your PR should include tests for any bug fixes or new features.
+- `cargo test` and `cargo clippy` must pass.
+
+You can run most of glam's tests locally by running the `build_and_test_features.sh` script.
+
+## Breaking changes
+
+*This section is optional. If there are no breaking changes, you can delete this section.*
+
+- If this PR is a breaking change describe how a user might need to migrate their code.
+- Simply adding new functionality is not a breaking change.
+- Fixing behavior that was definitely a bug is not a breaking change.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ab1b91b..f76c720 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,7 +27,7 @@ jobs:
       - name: Build-test documentation
         env:
           RUSTDOCFLAGS: -Dwarnings
-        run: cargo doc --all --all-features --no-deps --document-private-items --features rkyv/size_32
+        run: cargo doc --all --all-features --no-deps --document-private-items --features rkyv/pointer_width_32
 
   test:
     name: Test
diff --git a/Cargo.toml b/Cargo.toml
index 86272e2..06b7dac 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -41,21 +41,22 @@ fast-math = []
 # experimental nightly portable-simd support
 core-simd = []
 
+bytecheck = ["rkyv/bytecheck"]
+
 [dependencies]
 approx = { version = "0.5", optional = true, default-features = false }
 bytemuck = { version = "1.9", optional = true, default-features = false }
 mint = { version = "0.5.8", optional = true, default-features = false }
-rand = { version = "0.8", optional = true, default-features = false }
+rand = { version = "0.9", optional = true, default-features = false }
 serde = { version = "1.0", optional = true, default-features = false }
-rkyv = { version = "0.7", optional = true, default-features = false }
-bytecheck = { version = "0.7", optional = true, default-features = false }
-libm = { version = "0.2", optional = true, default-features = false}
+rkyv = { version = "0.8", optional = true, default-features = false }
+libm = { version = "0.2", optional = true, default-features = false }
 
 [dev-dependencies]
 # rand_xoshiro is required for tests if rand is enabled
-rand_xoshiro = "0.6"
-# Set a size_xx feature so that this crate compiles properly with --all-targets --all-features
-rkyv = { version = "0.7", default-features = false, features = ["size_32"] }
+rand_xoshiro = "0.7"
+# "alloc" is needed to support to_bytes()/deserialize() in tests.
+rkyv = { version = "0.8", default-features = false, features = ["alloc"] }
 serde_json = "1.0"
 
 [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
diff --git a/codegen/templates/vec.rs.tera b/codegen/templates/vec.rs.tera
index 9bf1f67..9f7cb75 100644
--- a/codegen/templates/vec.rs.tera
+++ b/codegen/templates/vec.rs.tera
@@ -2582,6 +2582,74 @@ impl {{ self_t }} {
 {% endif %}
 
 {% if not is_float %}
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        {% for c in components %}
+            let {{ c }} = match self.{{ c }}.checked_add(rhs.{{ c }}) { Some(v) => v, None => {return None} };
+        {%- endfor %}
+
+        Some(Self {
+            {% for c in components %}
+                {{ c }},
+            {%- endfor %}
+        })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        {% for c in components %}
+            let {{ c }} = match self.{{ c }}.checked_sub(rhs.{{ c }}) { Some(v) => v, None => {return None} };
+        {%- endfor %}
+
+        Some(Self {
+            {% for c in components %}
+                {{ c }},
+            {%- endfor %}
+        })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        {% for c in components %}
+            let {{ c }} = match self.{{ c }}.checked_mul(rhs.{{ c }}) { Some(v) => v, None => {return None} };
+        {%- endfor %}
+
+        Some(Self {
+            {% for c in components %}
+                {{ c }},
+            {%- endfor %}
+        })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        {% for c in components %}
+            let {{ c }} = match self.{{ c }}.checked_div(rhs.{{ c }}) { Some(v) => v, None => {return None} };
+        {%- endfor %}
+
+        Some(Self {
+            {% for c in components %}
+                {{ c }},
+            {%- endfor %}
+        })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -2686,6 +2754,40 @@ impl {{ self_t }} {
         }
     }
     {% if is_signed %}
+        /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+        ///
+        /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+        #[inline]
+        #[must_use]
+        pub const fn checked_add_unsigned(self, rhs: {{ opposite_signedness_t }}) -> Option<Self> {
+            {% for c in components %}
+                let {{ c }} = match self.{{ c }}.checked_add_unsigned(rhs.{{ c }}) { Some(v) => v, None => {return None} };
+            {%- endfor %}
+
+            Some(Self {
+                {% for c in components %}
+                    {{ c }},
+                {%- endfor %}
+            })
+        }
+
+        /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+        ///
+        /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+        #[inline]
+        #[must_use]
+        pub const fn checked_sub_unsigned(self, rhs: {{ opposite_signedness_t }}) -> Option<Self> {
+            {% for c in components %}
+                let {{ c }} = match self.{{ c }}.checked_sub_unsigned(rhs.{{ c }}) { Some(v) => v, None => {return None} };
+            {%- endfor %}
+
+            Some(Self {
+                {% for c in components %}
+                    {{ c }},
+                {%- endfor %}
+            })
+        }
+
         /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
         ///
         /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
@@ -2738,6 +2840,23 @@ impl {{ self_t }} {
             }
         }
     {% else %}
+        /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+        ///
+        /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+        #[inline]
+        #[must_use]
+        pub const fn checked_add_signed(self, rhs: {{ opposite_signedness_t }}) -> Option<Self> {
+            {% for c in components %}
+                let {{ c }} = match self.{{ c }}.checked_add_signed(rhs.{{ c }}) { Some(v) => v, None => {return None} };
+            {%- endfor %}
+
+            Some(Self {
+                {% for c in components %}
+                    {{ c }},
+                {%- endfor %}
+            })
+        }
+
         /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
         ///
         /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/features/impl_rand.rs b/src/features/impl_rand.rs
index 8f77c5f..c27484d 100644
--- a/src/features/impl_rand.rs
+++ b/src/features/impl_rand.rs
@@ -9,17 +9,17 @@ macro_rules! impl_vec_types {
     ) => {
         use super::{UniformVec2, UniformVec3, UniformVec4};
         use rand::{
-            distributions::{
-                uniform::{SampleBorrow, SampleUniform, UniformSampler},
-                Distribution, Standard,
+            distr::{
+                uniform::{Error as UniformError, SampleBorrow, SampleUniform, UniformSampler},
+                Distribution, StandardUniform,
             },
             Rng,
         };
 
-        impl Distribution<$vec2> for Standard {
+        impl Distribution<$vec2> for StandardUniform {
             #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $vec2 {
-                rng.gen::<[$t; 2]>().into()
+                rng.random::<[$t; 2]>().into()
             }
         }
 
@@ -30,97 +30,95 @@ macro_rules! impl_vec_types {
         impl UniformSampler for UniformVec2<$uniform<$t>> {
             type X = $vec2;
 
-            fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(low.x < high.x, "Uniform::new called with `low.x >= high.x");
-                assert!(low.y < high.y, "Uniform::new called with `low.y >= high.y");
-                Self {
-                    x_gen: $uniform::new(low.x, high.x),
-                    y_gen: $uniform::new(low.y, high.y),
+
+                if low.x >= high.x || low.y >= high.y {
+                    return Err(UniformError::EmptyRange);
                 }
+
+                Ok(Self {
+                    x_gen: $uniform::new(low.x, high.x)?,
+                    y_gen: $uniform::new(low.y, high.y)?,
+                })
             }
 
-            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::new_inclusive called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::new_inclusive called with `low.y >= high.y"
-                );
-                Self {
-                    x_gen: $uniform::new_inclusive(low.x, high.x),
-                    y_gen: $uniform::new_inclusive(low.y, high.y),
+
+                if low.x >= high.x || low.y >= high.y {
+                    return Err(UniformError::EmptyRange);
                 }
+
+                Ok(Self {
+                    x_gen: $uniform::new_inclusive(low.x, high.x)?,
+                    y_gen: $uniform::new_inclusive(low.y, high.y)?,
+                })
             }
 
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
                 Self::X::from([self.x_gen.sample(rng), self.y_gen.sample(rng)])
             }
 
-            fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Self::X
+            fn sample_single<R: Rng + ?Sized, B1, B2>(
+                low_b: B1,
+                high_b: B2,
+                rng: &mut R,
+            ) -> Result<Self::X, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::sample_single called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::sample_single called with `low.y >= high.y"
-                );
-                Self::X::from([
-                    $uniform::<$t>::sample_single(low.x, high.x, rng),
-                    $uniform::<$t>::sample_single(low.y, high.y, rng),
-                ])
+
+                if low.x >= high.x || low.y >= high.y {
+                    return Err(UniformError::EmptyRange);
+                }
+
+                Ok(Self::X::from([
+                    $uniform::<$t>::sample_single(low.x, high.x, rng)?,
+                    $uniform::<$t>::sample_single(low.y, high.y, rng)?,
+                ]))
             }
 
             fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
                 low_b: B1,
                 high_b: B2,
                 rng: &mut R,
-            ) -> Self::X
+            ) -> Result<Self::X, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::sample_single_inclusive called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::sample_single_inclusive called with `low.y >= high.y"
-                );
-                Self::X::from([
-                    $uniform::<$t>::sample_single_inclusive(low.x, high.x, rng),
-                    $uniform::<$t>::sample_single_inclusive(low.y, high.y, rng),
-                ])
+
+                if low.x >= high.x || low.y >= high.y {
+                    return Err(UniformError::EmptyRange);
+                }
+
+                Ok(Self::X::from([
+                    $uniform::<$t>::sample_single_inclusive(low.x, high.x, rng)?,
+                    $uniform::<$t>::sample_single_inclusive(low.y, high.y, rng)?,
+                ]))
             }
         }
 
-        impl Distribution<$vec3> for Standard {
+        impl Distribution<$vec3> for StandardUniform {
             #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $vec3 {
-                rng.gen::<[$t; 3]>().into()
+                rng.random::<[$t; 3]>().into()
             }
         }
 
@@ -131,47 +129,42 @@ macro_rules! impl_vec_types {
         impl UniformSampler for UniformVec3<$uniform<$t>> {
             type X = $vec3;
 
-            fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(low.x < high.x, "Uniform::new called with `low.x >= high.x");
-                assert!(low.y < high.y, "Uniform::new called with `low.y >= high.y");
-                assert!(low.z < high.z, "Uniform::new called with `low.z >= high.z");
-                Self {
-                    x_gen: $uniform::new(low.x, high.x),
-                    y_gen: $uniform::new(low.y, high.y),
-                    z_gen: $uniform::new(low.z, high.z),
+
+                if low.x >= high.x || low.y >= high.y || low.z >= high.z {
+                    return Err(UniformError::EmptyRange);
                 }
+
+                Ok(Self {
+                    x_gen: $uniform::new(low.x, high.x)?,
+                    y_gen: $uniform::new(low.y, high.y)?,
+                    z_gen: $uniform::new(low.z, high.z)?,
+                })
             }
 
-            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::new_inclusive called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::new_inclusive called with `low.y >= high.y"
-                );
-                assert!(
-                    low.z < high.z,
-                    "Uniform::new_inclusive called with `low.z >= high.z"
-                );
-                Self {
-                    x_gen: $uniform::new_inclusive(low.x, high.x),
-                    y_gen: $uniform::new_inclusive(low.y, high.y),
-                    z_gen: $uniform::new_inclusive(low.z, high.z),
+
+                if low.x >= high.x || low.y >= high.y || low.z >= high.z {
+                    return Err(UniformError::EmptyRange);
                 }
+
+                Ok(Self {
+                    x_gen: $uniform::new_inclusive(low.x, high.x)?,
+                    y_gen: $uniform::new_inclusive(low.y, high.y)?,
+                    z_gen: $uniform::new_inclusive(low.z, high.z)?,
+                })
             }
 
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
@@ -182,67 +175,57 @@ macro_rules! impl_vec_types {
                 ])
             }
 
-            fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Self::X
+            fn sample_single<R: Rng + ?Sized, B1, B2>(
+                low_b: B1,
+                high_b: B2,
+                rng: &mut R,
+            ) -> Result<Self::X, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::sample_single called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::sample_single called with `low.y >= high.y"
-                );
-                assert!(
-                    low.z < high.z,
-                    "Uniform::sample_single called with `low.z >= high.z"
-                );
-                Self::X::from([
-                    $uniform::<$t>::sample_single(low.x, high.x, rng),
-                    $uniform::<$t>::sample_single(low.y, high.y, rng),
-                    $uniform::<$t>::sample_single(low.z, high.z, rng),
-                ])
+
+                if low.x >= high.x || low.y >= high.y || low.z >= high.z {
+                    return Err(UniformError::EmptyRange);
+                }
+
+                Ok(Self::X::from([
+                    $uniform::<$t>::sample_single(low.x, high.x, rng)?,
+                    $uniform::<$t>::sample_single(low.y, high.y, rng)?,
+                    $uniform::<$t>::sample_single(low.z, high.z, rng)?,
+                ]))
             }
 
             fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
                 low_b: B1,
                 high_b: B2,
                 rng: &mut R,
-            ) -> Self::X
+            ) -> Result<Self::X, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::sample_single_inclusive called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::sample_single_inclusive called with `low.y >= high.y"
-                );
-                assert!(
-                    low.z < high.z,
-                    "Uniform::sample_single_inclusive called with `low.z >= high.z"
-                );
-                Self::X::from([
-                    $uniform::<$t>::sample_single_inclusive(low.x, high.x, rng),
-                    $uniform::<$t>::sample_single_inclusive(low.y, high.y, rng),
-                    $uniform::<$t>::sample_single_inclusive(low.z, high.z, rng),
-                ])
+
+                if low.x >= high.x || low.y >= high.y || low.z >= high.z {
+                    return Err(UniformError::EmptyRange);
+                }
+
+                Ok(Self::X::from([
+                    $uniform::<$t>::sample_single_inclusive(low.x, high.x, rng)?,
+                    $uniform::<$t>::sample_single_inclusive(low.y, high.y, rng)?,
+                    $uniform::<$t>::sample_single_inclusive(low.z, high.z, rng)?,
+                ]))
             }
         }
 
-        impl Distribution<$vec4> for Standard {
+        impl Distribution<$vec4> for StandardUniform {
             #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $vec4 {
-                rng.gen::<[$t; 4]>().into()
+                rng.random::<[$t; 4]>().into()
             }
         }
 
@@ -253,54 +236,44 @@ macro_rules! impl_vec_types {
         impl UniformSampler for UniformVec4<$uniform<$t>> {
             type X = $vec4;
 
-            fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(low.x < high.x, "Uniform::new called with `low.x >= high.x");
-                assert!(low.y < high.y, "Uniform::new called with `low.y >= high.y");
-                assert!(low.z < high.z, "Uniform::new called with `low.z >= high.z");
-                assert!(low.w < high.w, "Uniform::new called with `low.w >= high.w");
-                Self {
-                    x_gen: $uniform::new(low.x, high.x),
-                    y_gen: $uniform::new(low.y, high.y),
-                    z_gen: $uniform::new(low.z, high.z),
-                    w_gen: $uniform::new(low.w, high.w),
+
+                if low.x >= high.x || low.y >= high.y || low.z >= high.z || low.w >= high.w {
+                    return Err(UniformError::EmptyRange);
                 }
+
+                Ok(Self {
+                    x_gen: $uniform::new(low.x, high.x)?,
+                    y_gen: $uniform::new(low.y, high.y)?,
+                    z_gen: $uniform::new(low.z, high.z)?,
+                    w_gen: $uniform::new(low.w, high.w)?,
+                })
             }
 
-            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::new_inclusive called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::new_inclusive called with `low.y >= high.y"
-                );
-                assert!(
-                    low.z < high.z,
-                    "Uniform::new_inclusive called with `low.z >= high.z"
-                );
-                assert!(
-                    low.w < high.w,
-                    "Uniform::new_inclusive called with `low.w >= high.w"
-                );
-                Self {
-                    x_gen: $uniform::new_inclusive(low.x, high.x),
-                    y_gen: $uniform::new_inclusive(low.y, high.y),
-                    z_gen: $uniform::new_inclusive(low.z, high.z),
-                    w_gen: $uniform::new_inclusive(low.w, high.w),
+
+                if low.x >= high.x || low.y >= high.y || low.z >= high.z || low.w >= high.w {
+                    return Err(UniformError::EmptyRange);
                 }
+
+                Ok(Self {
+                    x_gen: $uniform::new_inclusive(low.x, high.x)?,
+                    y_gen: $uniform::new_inclusive(low.y, high.y)?,
+                    z_gen: $uniform::new_inclusive(low.z, high.z)?,
+                    w_gen: $uniform::new_inclusive(low.w, high.w)?,
+                })
             }
 
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
@@ -312,70 +285,52 @@ macro_rules! impl_vec_types {
                 ])
             }
 
-            fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Self::X
+            fn sample_single<R: Rng + ?Sized, B1, B2>(
+                low_b: B1,
+                high_b: B2,
+                rng: &mut R,
+            ) -> Result<Self::X, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::sample_single called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::sample_single called with `low.y >= high.y"
-                );
-                assert!(
-                    low.z < high.z,
-                    "Uniform::sample_single called with `low.z >= high.z"
-                );
-                assert!(
-                    low.w < high.w,
-                    "Uniform::sample_single called with `low.w >= high.w"
-                );
-                Self::X::from([
-                    $uniform::<$t>::sample_single(low.x, high.x, rng),
-                    $uniform::<$t>::sample_single(low.y, high.y, rng),
-                    $uniform::<$t>::sample_single(low.z, high.z, rng),
-                    $uniform::<$t>::sample_single(low.w, high.w, rng),
-                ])
+
+                if low.x >= high.x || low.y >= high.y || low.z >= high.z || low.w >= high.w {
+                    return Err(UniformError::EmptyRange);
+                }
+
+                Ok(Self::X::from([
+                    $uniform::<$t>::sample_single(low.x, high.x, rng)?,
+                    $uniform::<$t>::sample_single(low.y, high.y, rng)?,
+                    $uniform::<$t>::sample_single(low.z, high.z, rng)?,
+                    $uniform::<$t>::sample_single(low.w, high.w, rng)?,
+                ]))
             }
 
             fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
                 low_b: B1,
                 high_b: B2,
                 rng: &mut R,
-            ) -> Self::X
+            ) -> Result<Self::X, UniformError>
             where
                 B1: SampleBorrow<Self::X> + Sized,
                 B2: SampleBorrow<Self::X> + Sized,
             {
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
-                assert!(
-                    low.x < high.x,
-                    "Uniform::sample_single_inclusive called with `low.x >= high.x"
-                );
-                assert!(
-                    low.y < high.y,
-                    "Uniform::sample_single_inclusive called with `low.y >= high.y"
-                );
-                assert!(
-                    low.z < high.z,
-                    "Uniform::sample_single_inclusive called with `low.z >= high.z"
-                );
-                assert!(
-                    low.w < high.w,
-                    "Uniform::sample_single_inclusive called with `low.w >= high.w"
-                );
-                Self::X::from([
-                    $uniform::<$t>::sample_single_inclusive(low.x, high.x, rng),
-                    $uniform::<$t>::sample_single_inclusive(low.y, high.y, rng),
-                    $uniform::<$t>::sample_single_inclusive(low.z, high.z, rng),
-                    $uniform::<$t>::sample_single_inclusive(low.w, high.w, rng),
-                ])
+
+                if low.x >= high.x || low.y >= high.y || low.z >= high.z || low.w >= high.w {
+                    return Err(UniformError::EmptyRange);
+                }
+
+                Ok(Self::X::from([
+                    $uniform::<$t>::sample_single_inclusive(low.x, high.x, rng)?,
+                    $uniform::<$t>::sample_single_inclusive(low.y, high.y, rng)?,
+                    $uniform::<$t>::sample_single_inclusive(low.z, high.z, rng)?,
+                    $uniform::<$t>::sample_single_inclusive(low.w, high.w, rng)?,
+                ]))
             }
         }
 
@@ -384,9 +339,9 @@ macro_rules! impl_vec_types {
             use rand::{Rng, SeedableRng};
             use rand_xoshiro::Xoshiro256Plus;
             let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
-            let a: ($t, $t) = rng1.gen();
+            let a: ($t, $t) = rng1.random();
             let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
-            let b: $vec2 = rng2.gen();
+            let b: $vec2 = rng2.random();
             assert_eq!(a, b.into());
         }
 
@@ -395,9 +350,9 @@ macro_rules! impl_vec_types {
             use rand::{Rng, SeedableRng};
             use rand_xoshiro::Xoshiro256Plus;
             let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
-            let a: ($t, $t, $t) = rng1.gen();
+            let a: ($t, $t, $t) = rng1.random();
             let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
-            let b: $vec3 = rng2.gen();
+            let b: $vec3 = rng2.random();
             assert_eq!(a, b.into());
         }
 
@@ -406,9 +361,9 @@ macro_rules! impl_vec_types {
             use rand::{Rng, SeedableRng};
             use rand_xoshiro::Xoshiro256Plus;
             let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
-            let a: ($t, $t, $t, $t) = rng1.gen();
+            let a: ($t, $t, $t, $t) = rng1.random();
             let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
-            let b: $vec4 = rng2.gen();
+            let b: $vec4 = rng2.random();
             assert_eq!(a, b.into());
         }
 
@@ -463,7 +418,7 @@ macro_rules! test_vec_type_uniform {
         /// convert the result into the vector type.
         #[test]
         fn $equality_test_name() {
-            use rand::{distributions::Uniform, Rng, SeedableRng};
+            use rand::{distr::Uniform, Rng, SeedableRng};
             use rand_xoshiro::Xoshiro256Plus;
 
             let mut int_rng = Xoshiro256Plus::seed_from_u64(0);
@@ -478,8 +433,8 @@ macro_rules! test_vec_type_uniform {
                     $vec_low:expr,
                     $vec_high:expr
                 ) => {
-                    let int_u = Uniform::$uniform_function_name($t_low, $t_high);
-                    let vec_u = Uniform::$uniform_function_name($vec_low, $vec_high);
+                    let int_u = Uniform::$uniform_function_name($t_low, $t_high).unwrap();
+                    let vec_u = Uniform::$uniform_function_name($vec_low, $vec_high).unwrap();
 
                     let v_int = test_vec_type_uniform!(
                         __repeat_code $t_count,
@@ -535,14 +490,14 @@ macro_rules! test_vec_type_uniform {
                             <$t>::default(),
                             <$t>::MAX / $upper_range_divisor,
                             &mut int_rng,
-                        )
+                        ).unwrap()
                     );
 
                     let v_vec: $vec = <$vec as SampleUniform>::Sampler::$sampler_function_name(
                         $vec::default(),
                         $vec::MAX / $upper_range_divisor,
                         &mut vec_rng,
-                    );
+                    ).unwrap();
                     assert_eq!(v_int, v_vec.into());
                 };
             }
@@ -555,7 +510,7 @@ macro_rules! test_vec_type_uniform {
 
 macro_rules! impl_int_types {
     ($t:ty, $vec2:ident, $vec3:ident, $vec4:ident) => {
-        use rand::distributions::uniform::UniformInt;
+        use rand::distr::uniform::UniformInt;
 
         impl_vec_types!($t, $vec2, $vec3, $vec4, UniformInt, 1);
     };
@@ -563,39 +518,39 @@ macro_rules! impl_int_types {
 
 macro_rules! impl_float_types {
     ($t:ident, $mat2:ident, $mat3:ident, $mat4:ident, $quat:ident, $vec2:ident, $vec3:ident, $vec4:ident) => {
-        use rand::distributions::uniform::UniformFloat;
+        use rand::distr::uniform::UniformFloat;
 
         impl_vec_types!($t, $vec2, $vec3, $vec4, UniformFloat, 10.0);
 
-        impl Distribution<$mat2> for Standard {
+        impl Distribution<$mat2> for StandardUniform {
             #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $mat2 {
-                $mat2::from_cols_array(&rng.gen())
+                $mat2::from_cols_array(&rng.random())
             }
         }
 
-        impl Distribution<$mat3> for Standard {
+        impl Distribution<$mat3> for StandardUniform {
             #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $mat3 {
-                $mat3::from_cols_array(&rng.gen())
+                $mat3::from_cols_array(&rng.random())
             }
         }
 
-        impl Distribution<$mat4> for Standard {
+        impl Distribution<$mat4> for StandardUniform {
             #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $mat4 {
-                $mat4::from_cols_array(&rng.gen())
+                $mat4::from_cols_array(&rng.random())
             }
         }
 
-        impl Distribution<$quat> for Standard {
+        impl Distribution<$quat> for StandardUniform {
             #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $quat {
-                let z = rng.gen_range::<$t, _>(-1.0..=1.0);
-                let (y, x) = math::sin_cos(rng.gen_range::<$t, _>(0.0..TAU));
+                let z = rng.random_range::<$t, _>(-1.0..=1.0);
+                let (y, x) = math::sin_cos(rng.random_range::<$t, _>(0.0..TAU));
                 let r = math::sqrt(1.0 - z * z);
                 let axis = $vec3::new(r * x, r * y, z);
-                let angle = rng.gen_range::<$t, _>(0.0..TAU);
+                let angle = rng.random_range::<$t, _>(0.0..TAU);
                 $quat::from_axis_angle(axis, angle)
             }
         }
@@ -605,9 +560,9 @@ macro_rules! impl_float_types {
             use rand::{Rng, SeedableRng};
             use rand_xoshiro::Xoshiro256Plus;
             let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
-            let a = $mat2::from_cols_array(&rng1.gen::<[$t; 4]>());
+            let a = $mat2::from_cols_array(&rng1.random::<[$t; 4]>());
             let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
-            let b = rng2.gen::<$mat2>();
+            let b = rng2.random::<$mat2>();
             assert_eq!(a, b);
         }
 
@@ -616,9 +571,9 @@ macro_rules! impl_float_types {
             use rand::{Rng, SeedableRng};
             use rand_xoshiro::Xoshiro256Plus;
             let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
-            let a = $mat3::from_cols_array(&rng1.gen::<[$t; 9]>());
+            let a = $mat3::from_cols_array(&rng1.random::<[$t; 9]>());
             let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
-            let b = rng2.gen::<$mat3>();
+            let b = rng2.random::<$mat3>();
             assert_eq!(a, b);
         }
 
@@ -627,9 +582,9 @@ macro_rules! impl_float_types {
             use rand::{Rng, SeedableRng};
             use rand_xoshiro::Xoshiro256Plus;
             let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
-            let a = $mat4::from_cols_array(&rng1.gen::<[$t; 16]>());
+            let a = $mat4::from_cols_array(&rng1.random::<[$t; 16]>());
             let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
-            let b = rng2.gen::<$mat4>();
+            let b = rng2.random::<$mat4>();
             assert_eq!(a, b);
         }
 
@@ -638,10 +593,10 @@ macro_rules! impl_float_types {
             use rand::{Rng, SeedableRng};
             use rand_xoshiro::Xoshiro256Plus;
             let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
-            let a: $quat = rng1.gen();
+            let a: $quat = rng1.random();
             assert!(a.is_normalized());
             let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
-            let b: $quat = rng2.gen();
+            let b: $quat = rng2.random();
             assert_eq!(a, b);
         }
     };
@@ -675,10 +630,10 @@ mod f32 {
 
     impl_float_types!(f32, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec4);
 
-    impl Distribution<Vec3A> for Standard {
+    impl Distribution<Vec3A> for StandardUniform {
         #[inline]
         fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec3A {
-            rng.gen::<[f32; 3]>().into()
+            rng.random::<[f32; 3]>().into()
         }
     }
 
@@ -687,9 +642,9 @@ mod f32 {
         use rand::{Rng, SeedableRng};
         use rand_xoshiro::Xoshiro256Plus;
         let mut rng1 = Xoshiro256Plus::seed_from_u64(0);
-        let a: (f32, f32, f32) = rng1.gen();
+        let a: (f32, f32, f32) = rng1.random();
         let mut rng2 = Xoshiro256Plus::seed_from_u64(0);
-        let b: Vec3A = rng2.gen();
+        let b: Vec3A = rng2.random();
         assert_eq!(a, b.into());
     }
 }
diff --git a/src/features/impl_rkyv.rs b/src/features/impl_rkyv.rs
index 4db7ffc..1172301 100644
--- a/src/features/impl_rkyv.rs
+++ b/src/features/impl_rkyv.rs
@@ -1,15 +1,13 @@
 #[cfg(feature = "bytecheck")]
 macro_rules! impl_rkyv {
     (@bytecheck $type:ty) => {
-        impl<C: ?Sized> bytecheck::CheckBytes<C> for $type {
-            type Error = core::convert::Infallible;
-
+        unsafe impl<C: Fallible +?Sized> rkyv::bytecheck::CheckBytes<C> for $type {
             #[inline]
-            unsafe fn check_bytes<'a>(
-                value: *const Self,
+            unsafe fn check_bytes(
+                _value: *const Self,
                 _: &mut C,
-            ) -> Result<&'a Self, Self::Error> {
-                Ok(&*value)
+            ) -> Result<(), C::Error> {
+                Ok(())
             }
         }
     };
@@ -40,22 +38,25 @@ macro_rules! impl_rkyv_derive {
     };
 
     (@archive_deserialize $type:ty) => {
+        // SAFETY: All glam types have a fully defined data layout.
+        unsafe impl rkyv::traits::NoUndef for $type {}
+        // SAFETY: All glam types have a stable, well-defined layout that is identical on all
+        // targets.
+        unsafe impl rkyv::Portable for $type {}
         impl Archive for $type {
             type Archived = $type;
             type Resolver = ();
 
             #[inline]
-            unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) {
-                #[allow(unexpected_cfgs)]
-                out.write(to_archived!(*self as Self));
+            fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
+                out.write(*self)
             }
         }
 
         impl<D: Fallible + ?Sized> Deserialize<$type, D> for $type {
             #[inline]
             fn deserialize(&self, _: &mut D) -> Result<$type, D::Error> {
-                #[allow(unexpected_cfgs)]
-                Ok(from_archived!(*self))
+                Ok(*self)
             }
         }
     };
@@ -63,7 +64,7 @@ macro_rules! impl_rkyv_derive {
 
 mod f32 {
     use crate::{Affine2, Affine3A, Mat2, Mat3, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
     impl_rkyv!(Affine2);
     impl_rkyv!(Affine3A);
     impl_rkyv!(Mat2);
@@ -79,7 +80,7 @@ mod f32 {
 
 mod f64 {
     use crate::{DAffine2, DAffine3, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(DAffine2);
     impl_rkyv!(DAffine3);
@@ -94,7 +95,7 @@ mod f64 {
 
 mod i8 {
     use crate::{I8Vec2, I8Vec3, I8Vec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(I8Vec2);
     impl_rkyv!(I8Vec3);
@@ -103,7 +104,7 @@ mod i8 {
 
 mod i16 {
     use crate::{I16Vec2, I16Vec3, I16Vec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(I16Vec2);
     impl_rkyv!(I16Vec3);
@@ -112,7 +113,7 @@ mod i16 {
 
 mod i32 {
     use crate::{IVec2, IVec3, IVec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(IVec2);
     impl_rkyv!(IVec3);
@@ -121,7 +122,7 @@ mod i32 {
 
 mod i64 {
     use crate::{I64Vec2, I64Vec3, I64Vec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(I64Vec2);
     impl_rkyv!(I64Vec3);
@@ -130,7 +131,7 @@ mod i64 {
 
 mod u8 {
     use crate::{U8Vec2, U8Vec3, U8Vec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(U8Vec2);
     impl_rkyv!(U8Vec3);
@@ -139,7 +140,7 @@ mod u8 {
 
 mod u16 {
     use crate::{U16Vec2, U16Vec3, U16Vec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(U16Vec2);
     impl_rkyv!(U16Vec3);
@@ -148,7 +149,7 @@ mod u16 {
 
 mod u32 {
     use crate::{UVec2, UVec3, UVec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(UVec2);
     impl_rkyv!(UVec3);
@@ -157,7 +158,7 @@ mod u32 {
 
 mod u64 {
     use crate::{U64Vec2, U64Vec3, U64Vec4};
-    use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
+    use rkyv::{rancor::Fallible, Archive, Deserialize, Place, Serialize};
 
     impl_rkyv!(U64Vec2);
     impl_rkyv!(U64Vec3);
@@ -166,27 +167,36 @@ mod u64 {
 
 #[cfg(test)]
 mod test {
-    pub type DefaultSerializer = rkyv::ser::serializers::CoreSerializer<256, 256>;
-    pub type DefaultDeserializer = rkyv::Infallible;
-    use rkyv::ser::Serializer;
-    use rkyv::*;
+    /// The serializer type expected by [`rkyv::to_bytes()`].
+    pub type TestSerializer<'a> = rkyv::api::high::HighSerializer<
+        rkyv::util::AlignedVec,
+        rkyv::ser::allocator::ArenaHandle<'a>,
+        rkyv::rancor::Panic,
+    >;
+    /// The deserializer type expected by [`rkyv::deserialize()`].
+    pub type TestDeserializer = rkyv::api::high::HighDeserializer<rkyv::rancor::Panic>;
+    pub type TestValidator<'a> = rkyv::api::high::HighValidator<'a, rkyv::rancor::Panic>;
     pub fn test_archive<T>(value: &T)
     where
-        T: core::fmt::Debug + PartialEq + rkyv::Serialize<DefaultSerializer>,
-        T::Archived: core::fmt::Debug + PartialEq<T> + rkyv::Deserialize<T, DefaultDeserializer>,
+        T: core::fmt::Debug
+            + PartialEq
+            + rkyv::Portable
+            + for<'a> rkyv::Serialize<TestSerializer<'a>>,
+        T::Archived: core::fmt::Debug + PartialEq<T> + rkyv::Deserialize<T, TestDeserializer>,
+        // #[cfg(feature = "bytecheck")]
+        T::Archived: for<'a> rkyv::bytecheck::CheckBytes<TestValidator<'a>>,
     {
-        let mut serializer = DefaultSerializer::default();
-        serializer
-            .serialize_value(value)
-            .expect("failed to archive value");
-        let len = serializer.pos();
-        let buffer = serializer.into_serializer().into_inner();
-
-        let archived_value = unsafe { rkyv::archived_root::<T>(&buffer[0..len]) };
+        let buffer = rkyv::to_bytes(value).unwrap();
+
+        #[cfg(feature = "bytecheck")]
+        {
+            let archived_value = rkyv::access::<T::Archived, rkyv::rancor::Panic>(&buffer).unwrap();
+            assert_eq!(archived_value, value);
+        }
+        let archived_value = unsafe { rkyv::access_unchecked::<T::Archived>(&buffer) };
         assert_eq!(archived_value, value);
-        let mut deserializer = DefaultDeserializer::default();
         assert_eq!(
-            &archived_value.deserialize(&mut deserializer).unwrap(),
+            &rkyv::deserialize::<T, rkyv::rancor::Panic>(archived_value).unwrap(),
             value
         );
     }
diff --git a/src/i16/i16vec2.rs b/src/i16/i16vec2.rs
index 4516083..1d27fc3 100644
--- a/src/i16/i16vec2.rs
+++ b/src/i16/i16vec2.rs
@@ -512,6 +512,78 @@ impl I16Vec2 {
         crate::U64Vec2::new(self.x as u64, self.y as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -608,6 +680,42 @@ impl I16Vec2 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U16Vec2) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U16Vec2) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i16/i16vec3.rs b/src/i16/i16vec3.rs
index b29a214..d14ff78 100644
--- a/src/i16/i16vec3.rs
+++ b/src/i16/i16vec3.rs
@@ -555,6 +555,94 @@ impl I16Vec3 {
         crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -659,6 +747,50 @@ impl I16Vec3 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U16Vec3) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U16Vec3) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i16/i16vec4.rs b/src/i16/i16vec4.rs
index de137d6..de41177 100644
--- a/src/i16/i16vec4.rs
+++ b/src/i16/i16vec4.rs
@@ -585,6 +585,110 @@ impl I16Vec4 {
         crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_mul(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_div(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -697,6 +801,58 @@ impl I16Vec4 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U16Vec4) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add_unsigned(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U16Vec4) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub_unsigned(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i32/ivec2.rs b/src/i32/ivec2.rs
index 5743abb..41c3d75 100644
--- a/src/i32/ivec2.rs
+++ b/src/i32/ivec2.rs
@@ -512,6 +512,78 @@ impl IVec2 {
         crate::U64Vec2::new(self.x as u64, self.y as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -608,6 +680,42 @@ impl IVec2 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: UVec2) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: UVec2) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i32/ivec3.rs b/src/i32/ivec3.rs
index e89ef0b..54b904f 100644
--- a/src/i32/ivec3.rs
+++ b/src/i32/ivec3.rs
@@ -555,6 +555,94 @@ impl IVec3 {
         crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -659,6 +747,50 @@ impl IVec3 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: UVec3) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: UVec3) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i32/ivec4.rs b/src/i32/ivec4.rs
index 1da0f92..e1fceeb 100644
--- a/src/i32/ivec4.rs
+++ b/src/i32/ivec4.rs
@@ -585,6 +585,110 @@ impl IVec4 {
         crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_mul(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_div(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -697,6 +801,58 @@ impl IVec4 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: UVec4) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add_unsigned(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: UVec4) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub_unsigned(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i64/i64vec2.rs b/src/i64/i64vec2.rs
index 8c11046..0d8c4ed 100644
--- a/src/i64/i64vec2.rs
+++ b/src/i64/i64vec2.rs
@@ -512,6 +512,78 @@ impl I64Vec2 {
         crate::U64Vec2::new(self.x as u64, self.y as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -608,6 +680,42 @@ impl I64Vec2 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U64Vec2) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U64Vec2) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i64/i64vec3.rs b/src/i64/i64vec3.rs
index 8618869..0d79b86 100644
--- a/src/i64/i64vec3.rs
+++ b/src/i64/i64vec3.rs
@@ -555,6 +555,94 @@ impl I64Vec3 {
         crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -659,6 +747,50 @@ impl I64Vec3 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U64Vec3) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U64Vec3) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i64/i64vec4.rs b/src/i64/i64vec4.rs
index bb78b6b..26dc2cf 100644
--- a/src/i64/i64vec4.rs
+++ b/src/i64/i64vec4.rs
@@ -585,6 +585,110 @@ impl I64Vec4 {
         crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_mul(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_div(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -697,6 +801,58 @@ impl I64Vec4 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U64Vec4) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add_unsigned(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U64Vec4) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub_unsigned(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i8/i8vec2.rs b/src/i8/i8vec2.rs
index 284aac0..fec3c64 100644
--- a/src/i8/i8vec2.rs
+++ b/src/i8/i8vec2.rs
@@ -512,6 +512,78 @@ impl I8Vec2 {
         crate::U64Vec2::new(self.x as u64, self.y as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -608,6 +680,42 @@ impl I8Vec2 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U8Vec2) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U8Vec2) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i8/i8vec3.rs b/src/i8/i8vec3.rs
index 400ac93..c4d7e67 100644
--- a/src/i8/i8vec3.rs
+++ b/src/i8/i8vec3.rs
@@ -555,6 +555,94 @@ impl I8Vec3 {
         crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -659,6 +747,50 @@ impl I8Vec3 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U8Vec3) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U8Vec3) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/i8/i8vec4.rs b/src/i8/i8vec4.rs
index 5ba0ce7..a373d28 100644
--- a/src/i8/i8vec4.rs
+++ b/src/i8/i8vec4.rs
@@ -585,6 +585,110 @@ impl I8Vec4 {
         crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_mul(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_div(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -697,6 +801,58 @@ impl I8Vec4 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_unsigned(self, rhs: U8Vec4) -> Option<Self> {
+        let x = match self.x.checked_add_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add_unsigned(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and unsigned vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub_unsigned(self, rhs: U8Vec4) -> Option<Self> {
+        let x = match self.x.checked_sub_unsigned(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub_unsigned(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub_unsigned(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub_unsigned(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and unsigned vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_unsigned(rhs.x), self.y.wrapping_add_unsigned(rhs.y), ..]`.
diff --git a/src/u16/u16vec2.rs b/src/u16/u16vec2.rs
index 47987c9..a5d68f9 100644
--- a/src/u16/u16vec2.rs
+++ b/src/u16/u16vec2.rs
@@ -407,6 +407,78 @@ impl U16Vec2 {
         crate::U64Vec2::new(self.x as u64, self.y as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -503,6 +575,24 @@ impl U16Vec2 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I16Vec2) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u16/u16vec3.rs b/src/u16/u16vec3.rs
index 5632671..5d199e2 100644
--- a/src/u16/u16vec3.rs
+++ b/src/u16/u16vec3.rs
@@ -468,6 +468,94 @@ impl U16Vec3 {
         crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -572,6 +660,28 @@ impl U16Vec3 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I16Vec3) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_signed(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u16/u16vec4.rs b/src/u16/u16vec4.rs
index 60c94ae..fad1739 100644
--- a/src/u16/u16vec4.rs
+++ b/src/u16/u16vec4.rs
@@ -490,6 +490,110 @@ impl U16Vec4 {
         crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_mul(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_div(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -602,6 +706,32 @@ impl U16Vec4 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I16Vec4) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_signed(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add_signed(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u32/uvec2.rs b/src/u32/uvec2.rs
index 1752654..ab3f212 100644
--- a/src/u32/uvec2.rs
+++ b/src/u32/uvec2.rs
@@ -407,6 +407,78 @@ impl UVec2 {
         crate::U64Vec2::new(self.x as u64, self.y as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -503,6 +575,24 @@ impl UVec2 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: IVec2) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u32/uvec3.rs b/src/u32/uvec3.rs
index 98b5c9b..a485b63 100644
--- a/src/u32/uvec3.rs
+++ b/src/u32/uvec3.rs
@@ -468,6 +468,94 @@ impl UVec3 {
         crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -572,6 +660,28 @@ impl UVec3 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: IVec3) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_signed(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u32/uvec4.rs b/src/u32/uvec4.rs
index 077d4af..b6fcd7f 100644
--- a/src/u32/uvec4.rs
+++ b/src/u32/uvec4.rs
@@ -490,6 +490,110 @@ impl UVec4 {
         crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_mul(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_div(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -602,6 +706,32 @@ impl UVec4 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: IVec4) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_signed(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add_signed(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u64/u64vec2.rs b/src/u64/u64vec2.rs
index 5461fc9..624ee8a 100644
--- a/src/u64/u64vec2.rs
+++ b/src/u64/u64vec2.rs
@@ -407,6 +407,78 @@ impl U64Vec2 {
         crate::I64Vec2::new(self.x as i64, self.y as i64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -503,6 +575,24 @@ impl U64Vec2 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I64Vec2) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u64/u64vec3.rs b/src/u64/u64vec3.rs
index 92391ff..24ec916 100644
--- a/src/u64/u64vec3.rs
+++ b/src/u64/u64vec3.rs
@@ -468,6 +468,94 @@ impl U64Vec3 {
         crate::I64Vec3::new(self.x as i64, self.y as i64, self.z as i64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -572,6 +660,28 @@ impl U64Vec3 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I64Vec3) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_signed(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u64/u64vec4.rs b/src/u64/u64vec4.rs
index 3f3ebb2..053e2db 100644
--- a/src/u64/u64vec4.rs
+++ b/src/u64/u64vec4.rs
@@ -490,6 +490,110 @@ impl U64Vec4 {
         crate::I64Vec4::new(self.x as i64, self.y as i64, self.z as i64, self.w as i64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_mul(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_div(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -602,6 +706,32 @@ impl U64Vec4 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I64Vec4) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_signed(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add_signed(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u8/u8vec2.rs b/src/u8/u8vec2.rs
index 4a93faa..e4bfaf0 100644
--- a/src/u8/u8vec2.rs
+++ b/src/u8/u8vec2.rs
@@ -407,6 +407,78 @@ impl U8Vec2 {
         crate::U64Vec2::new(self.x as u64, self.y as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -503,6 +575,24 @@ impl U8Vec2 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I8Vec2) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u8/u8vec3.rs b/src/u8/u8vec3.rs
index ecaa95a..38228d9 100644
--- a/src/u8/u8vec3.rs
+++ b/src/u8/u8vec3.rs
@@ -468,6 +468,94 @@ impl U8Vec3 {
         crate::U64Vec3::new(self.x as u64, self.y as u64, self.z as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -572,6 +660,28 @@ impl U8Vec3 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I8Vec3) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_signed(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.
diff --git a/src/u8/u8vec4.rs b/src/u8/u8vec4.rs
index 7593e3a..da15d45 100644
--- a/src/u8/u8vec4.rs
+++ b/src/u8/u8vec4.rs
@@ -490,6 +490,110 @@ impl U8Vec4 {
         crate::U64Vec4::new(self.x as u64, self.y as u64, self.z as u64, self.w as u64)
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_add(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping subtraction of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x - rhs.x, self.y - rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_sub(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_sub(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_sub(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_sub(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping multiplication of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x * rhs.x, self.y * rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_mul(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_mul(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_mul(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_mul(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
+    /// Returns a vector containing the wrapping division of `self` and `rhs`.
+    ///
+    /// In other words this computes `Some([self.x / rhs.x, self.y / rhs.y, ..])` but returns `None` on any division by zero.
+    #[inline]
+    #[must_use]
+    pub const fn checked_div(self, rhs: Self) -> Option<Self> {
+        let x = match self.x.checked_div(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_div(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_div(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_div(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add(rhs.x), self.y.wrapping_add(rhs.y), ..]`.
@@ -602,6 +706,32 @@ impl U8Vec4 {
         }
     }
 
+    /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
+    ///
+    /// In other words this computes `Some([self.x + rhs.x, self.y + rhs.y, ..])` but returns `None` on any overflow.
+    #[inline]
+    #[must_use]
+    pub const fn checked_add_signed(self, rhs: I8Vec4) -> Option<Self> {
+        let x = match self.x.checked_add_signed(rhs.x) {
+            Some(v) => v,
+            None => return None,
+        };
+        let y = match self.y.checked_add_signed(rhs.y) {
+            Some(v) => v,
+            None => return None,
+        };
+        let z = match self.z.checked_add_signed(rhs.z) {
+            Some(v) => v,
+            None => return None,
+        };
+        let w = match self.w.checked_add_signed(rhs.w) {
+            Some(v) => v,
+            None => return None,
+        };
+
+        Some(Self { x, y, z, w })
+    }
+
     /// Returns a vector containing the wrapping addition of `self` and signed vector `rhs`.
     ///
     /// In other words this computes `[self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y), ..]`.


Test patch:
diff --git a/build_and_test_features.sh b/build_and_test_features.sh
index 98c39a6..30f1d98 100755
--- a/build_and_test_features.sh
+++ b/build_and_test_features.sh
@@ -2,19 +2,22 @@
 
 set -ex
 
+# Supported dependencies
+DEPENDENCIES="approx bytemuck mint rand rkyv serde debug-glam-assert"
+
 # Set of features to build & test.
 FEATURE_SETS=(
   # std
   "std"
-  "std approx bytemuck mint rand serde debug-glam-assert"
-  "std scalar-math approx bytemuck mint rand serde debug-glam-assert"
+  "std $DEPENDENCIES"
+  "std scalar-math $DEPENDENCIES"
   "std cuda"
   "std scalar-math cuda"
   "std libm"
   "std scalar-math libm"
   # no_std
   "libm"
-  "libm scalar-math approx bytemuck mint rand serde debug-glam-assert"
+  "libm scalar-math $DEPENDENCIES"
 )
 
 rustc --version
diff --git a/tests/vec2.rs b/tests/vec2.rs
index 9c4a63b..2c36415 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -730,9 +730,46 @@ macro_rules! impl_vec2_signed_integer_tests {
         impl_vec2_signed_tests!($t, $new, $vec2, $vec3, $mask, $masknew);
 
         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);
+            assert_eq!($vec2::ZERO.signum(), $vec2::ZERO);
+            assert_eq!($vec2::ONE.signum(), $vec2::ONE);
+            assert_eq!((-$vec2::ONE).signum(), -$vec2::ONE);
+        });
+
+        glam_test!(test_checked_add, {
+            assert_eq!($vec2::MAX.checked_add($vec2::ONE), None);
+            assert_eq!($vec2::MAX.checked_add($vec2::X), None);
+            assert_eq!($vec2::MAX.checked_add($vec2::Y), None);
+            assert_eq!($vec2::MAX.checked_add($vec2::ZERO), Some($vec2::MAX));
+        });
+
+        glam_test!(test_checked_sub, {
+            assert_eq!($vec2::MIN.checked_sub($vec2::ONE), None);
+            assert_eq!($vec2::MIN.checked_sub($vec2::X), None);
+            assert_eq!($vec2::MIN.checked_sub($vec2::Y), None);
+            assert_eq!($vec2::MIN.checked_sub($vec2::ZERO), Some($vec2::MIN));
+        });
+
+        glam_test!(test_checked_mul, {
+            assert_eq!($vec2::MIN.checked_mul($vec2::MIN), None);
+            assert_eq!($vec2::MAX.checked_mul($vec2::MIN), None);
+            assert_eq!($vec2::MIN.checked_mul($vec2::MAX), None);
+            assert_eq!($vec2::MAX.checked_mul($vec2::MAX), None);
+            assert_eq!($vec2::ZERO.checked_mul($vec2::MIN), Some($vec2::ZERO));
+            assert_eq!($vec2::MAX.checked_mul($vec2::ZERO), Some($vec2::ZERO));
+            assert_eq!($vec2::MIN.checked_mul($vec2::ONE), Some($vec2::MIN));
+            assert_eq!($vec2::MAX.checked_mul($vec2::ONE), Some($vec2::MAX));
+            assert_eq!($vec2::ZERO.checked_mul($vec2::ZERO), Some($vec2::ZERO));
+            assert_eq!($vec2::ONE.checked_mul($vec2::ONE), Some($vec2::ONE));
+        });
+
+        glam_test!(test_checked_div, {
+            assert_eq!($vec2::MIN.checked_div($vec2::ZERO), None);
+            assert_eq!($vec2::MAX.checked_div($vec2::ZERO), None);
+            assert_eq!($vec2::MAX.checked_div($vec2::X), None);
+            assert_eq!($vec2::MAX.checked_div($vec2::Y), None);
+            assert_eq!($vec2::ZERO.checked_div($vec2::ONE), Some($vec2::ZERO));
+            assert_eq!($vec2::MIN.checked_div($vec2::ONE), Some($vec2::MIN));
+            assert_eq!($vec2::MAX.checked_div($vec2::ONE), Some($vec2::MAX));
         });
 
         glam_test!(test_manhattan_distance, {
@@ -778,6 +815,36 @@ macro_rules! impl_vec2_unsigned_integer_tests {
     ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
         impl_vec2_tests!($t, $new, $vec2, $vec3, $mask, $masknew);
 
+        glam_test!(test_checked_add, {
+            assert_eq!($vec2::MAX.checked_add($vec2::ONE), None);
+            assert_eq!($vec2::MAX.checked_add($vec2::X), None);
+            assert_eq!($vec2::MAX.checked_add($vec2::Y), None);
+            assert_eq!($vec2::MAX.checked_add($vec2::ZERO), Some($vec2::MAX));
+        });
+
+        glam_test!(test_checked_sub, {
+            assert_eq!($vec2::ZERO.checked_sub($vec2::ONE), None);
+            assert_eq!($vec2::ZERO.checked_sub($vec2::X), None);
+            assert_eq!($vec2::ZERO.checked_sub($vec2::Y), None);
+            assert_eq!($vec2::ZERO.checked_sub($vec2::ZERO), Some($vec2::MIN));
+        });
+
+        glam_test!(test_checked_mul, {
+            assert_eq!($vec2::MAX.checked_mul($vec2::MAX), None);
+            assert_eq!($vec2::MAX.checked_mul($vec2::ZERO), Some($vec2::ZERO));
+            assert_eq!($vec2::MAX.checked_mul($vec2::ONE), Some($vec2::MAX));
+            assert_eq!($vec2::ZERO.checked_mul($vec2::ZERO), Some($vec2::ZERO));
+            assert_eq!($vec2::ONE.checked_mul($vec2::ONE), Some($vec2::ONE));
+        });
+
+        glam_test!(test_checked_div, {
+            assert_eq!($vec2::MAX.checked_div($vec2::ZERO), None);
+            assert_eq!($vec2::MAX.checked_div($vec2::X), None);
+            assert_eq!($vec2::MAX.checked_div($vec2::Y), None);
+            assert_eq!($vec2::ZERO.checked_div($vec2::ONE), Some($vec2::ZERO));
+            assert_eq!($vec2::MAX.checked_div($vec2::ONE), Some($vec2::MAX));
+        });
+
         glam_test!(test_manhattan_distance, {
             assert_eq!($vec2::new(5, 2).manhattan_distance($vec2::new(23, 16)), 32);
             assert_eq!($vec2::new(30, 11).manhattan_distance($vec2::new(30, 11)), 0);
@@ -1613,6 +1680,22 @@ mod i8vec2 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I8Vec2::MAX.checked_add_unsigned(U8Vec2::ONE), None);
+        assert_eq!(
+            I8Vec2::NEG_ONE.checked_add_unsigned(U8Vec2::ONE),
+            Some(I8Vec2::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I8Vec2::MIN.checked_sub_unsigned(U8Vec2::ONE), None);
+        assert_eq!(
+            I8Vec2::ZERO.checked_sub_unsigned(U8Vec2::ONE),
+            Some(I8Vec2::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I8Vec2::new(i8::MAX, i8::MAX).wrapping_add_unsigned(U8Vec2::new(1, 1)),
@@ -1916,6 +1999,22 @@ mod i16vec2 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I16Vec2::MAX.checked_add_unsigned(U16Vec2::ONE), None);
+        assert_eq!(
+            I16Vec2::NEG_ONE.checked_add_unsigned(U16Vec2::ONE),
+            Some(I16Vec2::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I16Vec2::MIN.checked_sub_unsigned(U16Vec2::ONE), None);
+        assert_eq!(
+            I16Vec2::ZERO.checked_sub_unsigned(U16Vec2::ONE),
+            Some(I16Vec2::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I16Vec2::new(i16::MAX, i16::MAX).wrapping_add_unsigned(U16Vec2::new(1, 1)),
@@ -2197,6 +2296,22 @@ mod ivec2 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(IVec2::MAX.checked_add_unsigned(UVec2::ONE), None);
+        assert_eq!(
+            IVec2::NEG_ONE.checked_add_unsigned(UVec2::ONE),
+            Some(IVec2::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(IVec2::MIN.checked_sub_unsigned(UVec2::ONE), None);
+        assert_eq!(
+            IVec2::ZERO.checked_sub_unsigned(UVec2::ONE),
+            Some(IVec2::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             IVec2::new(i32::MAX, i32::MAX).wrapping_add_unsigned(UVec2::new(1, 1)),
@@ -2406,6 +2521,22 @@ mod i64vec2 {
         assert!(I64Vec2::try_from(U64Vec2::new(1, u64::MAX)).is_err());
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I64Vec2::MAX.checked_add_unsigned(U64Vec2::ONE), None);
+        assert_eq!(
+            I64Vec2::NEG_ONE.checked_add_unsigned(U64Vec2::ONE),
+            Some(I64Vec2::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I64Vec2::MIN.checked_sub_unsigned(U64Vec2::ONE), None);
+        assert_eq!(
+            I64Vec2::ZERO.checked_sub_unsigned(U64Vec2::ONE),
+            Some(I64Vec2::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I64Vec2::new(i64::MAX, i64::MAX).wrapping_add_unsigned(U64Vec2::new(1, 1)),
diff --git a/tests/vec3.rs b/tests/vec3.rs
index 8fa3e6d..5ab9135 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -850,6 +850,46 @@ macro_rules! impl_vec3_signed_integer_tests {
             assert_eq!((-$vec3::ONE).signum(), -$vec3::ONE);
         });
 
+        glam_test!(test_checked_add, {
+            assert_eq!($vec3::MAX.checked_add($vec3::ONE), None);
+            assert_eq!($vec3::MAX.checked_add($vec3::X), None);
+            assert_eq!($vec3::MAX.checked_add($vec3::Y), None);
+            assert_eq!($vec3::MAX.checked_add($vec3::Z), None);
+            assert_eq!($vec3::MAX.checked_add($vec3::ZERO), Some($vec3::MAX));
+        });
+
+        glam_test!(test_checked_sub, {
+            assert_eq!($vec3::MIN.checked_sub($vec3::ONE), None);
+            assert_eq!($vec3::MIN.checked_sub($vec3::X), None);
+            assert_eq!($vec3::MIN.checked_sub($vec3::Y), None);
+            assert_eq!($vec3::MIN.checked_sub($vec3::Z), None);
+            assert_eq!($vec3::MIN.checked_sub($vec3::ZERO), Some($vec3::MIN));
+        });
+
+        glam_test!(test_checked_mul, {
+            assert_eq!($vec3::MIN.checked_mul($vec3::MIN), None);
+            assert_eq!($vec3::MAX.checked_mul($vec3::MIN), None);
+            assert_eq!($vec3::MIN.checked_mul($vec3::MAX), None);
+            assert_eq!($vec3::MAX.checked_mul($vec3::MAX), None);
+            assert_eq!($vec3::ZERO.checked_mul($vec3::MIN), Some($vec3::ZERO));
+            assert_eq!($vec3::MAX.checked_mul($vec3::ZERO), Some($vec3::ZERO));
+            assert_eq!($vec3::MIN.checked_mul($vec3::ONE), Some($vec3::MIN));
+            assert_eq!($vec3::MAX.checked_mul($vec3::ONE), Some($vec3::MAX));
+            assert_eq!($vec3::ZERO.checked_mul($vec3::ZERO), Some($vec3::ZERO));
+            assert_eq!($vec3::ONE.checked_mul($vec3::ONE), Some($vec3::ONE));
+        });
+
+        glam_test!(test_checked_div, {
+            assert_eq!($vec3::MIN.checked_div($vec3::ZERO), None);
+            assert_eq!($vec3::MAX.checked_div($vec3::ZERO), None);
+            assert_eq!($vec3::MAX.checked_div($vec3::X), None);
+            assert_eq!($vec3::MAX.checked_div($vec3::Y), None);
+            assert_eq!($vec3::MAX.checked_div($vec3::Z), None);
+            assert_eq!($vec3::ZERO.checked_div($vec3::ONE), Some($vec3::ZERO));
+            assert_eq!($vec3::MIN.checked_div($vec3::ONE), Some($vec3::MIN));
+            assert_eq!($vec3::MAX.checked_div($vec3::ONE), Some($vec3::MAX));
+        });
+
         glam_test!(test_manhattan_distance, {
             assert_eq!(
                 $vec3::new(3, 27, 98).manhattan_distance($vec3::new(20, 65, 97)),
@@ -908,6 +948,39 @@ macro_rules! impl_vec3_unsigned_integer_tests {
     ($t:ident, $new:ident, $vec3:ident, $mask:ident, $masknew:ident) => {
         impl_vec3_tests!($t, $new, $vec3, $mask, $masknew);
 
+        glam_test!(test_checked_add, {
+            assert_eq!($vec3::MAX.checked_add($vec3::ONE), None);
+            assert_eq!($vec3::MAX.checked_add($vec3::X), None);
+            assert_eq!($vec3::MAX.checked_add($vec3::Y), None);
+            assert_eq!($vec3::MAX.checked_add($vec3::Z), None);
+            assert_eq!($vec3::MAX.checked_add($vec3::ZERO), Some($vec3::MAX));
+        });
+
+        glam_test!(test_checked_sub, {
+            assert_eq!($vec3::ZERO.checked_sub($vec3::ONE), None);
+            assert_eq!($vec3::ZERO.checked_sub($vec3::X), None);
+            assert_eq!($vec3::ZERO.checked_sub($vec3::Y), None);
+            assert_eq!($vec3::ZERO.checked_sub($vec3::Z), None);
+            assert_eq!($vec3::ZERO.checked_sub($vec3::ZERO), Some($vec3::MIN));
+        });
+
+        glam_test!(test_checked_mul, {
+            assert_eq!($vec3::MAX.checked_mul($vec3::MAX), None);
+            assert_eq!($vec3::MAX.checked_mul($vec3::ZERO), Some($vec3::ZERO));
+            assert_eq!($vec3::MAX.checked_mul($vec3::ONE), Some($vec3::MAX));
+            assert_eq!($vec3::ZERO.checked_mul($vec3::ZERO), Some($vec3::ZERO));
+            assert_eq!($vec3::ONE.checked_mul($vec3::ONE), Some($vec3::ONE));
+        });
+
+        glam_test!(test_checked_div, {
+            assert_eq!($vec3::MAX.checked_div($vec3::ZERO), None);
+            assert_eq!($vec3::MAX.checked_div($vec3::X), None);
+            assert_eq!($vec3::MAX.checked_div($vec3::Y), None);
+            assert_eq!($vec3::MAX.checked_div($vec3::Z), None);
+            assert_eq!($vec3::ZERO.checked_div($vec3::ONE), Some($vec3::ZERO));
+            assert_eq!($vec3::MAX.checked_div($vec3::ONE), Some($vec3::MAX));
+        });
+
         glam_test!(test_manhattan_distance, {
             assert_eq!(
                 $vec3::new(3, 27, 98).manhattan_distance($vec3::new(20, 65, 97)),
@@ -2026,6 +2099,22 @@ mod i8vec3 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I8Vec3::MAX.checked_add_unsigned(U8Vec3::ONE), None);
+        assert_eq!(
+            I8Vec3::NEG_ONE.checked_add_unsigned(U8Vec3::ONE),
+            Some(I8Vec3::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I8Vec3::MIN.checked_sub_unsigned(U8Vec3::ONE), None);
+        assert_eq!(
+            I8Vec3::ZERO.checked_sub_unsigned(U8Vec3::ONE),
+            Some(I8Vec3::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I8Vec3::new(i8::MAX, i8::MAX, i8::MAX).wrapping_add_unsigned(U8Vec3::new(1, 1, 1)),
@@ -2337,6 +2426,22 @@ mod i16vec3 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I16Vec3::MAX.checked_add_unsigned(U16Vec3::ONE), None);
+        assert_eq!(
+            I16Vec3::NEG_ONE.checked_add_unsigned(U16Vec3::ONE),
+            Some(I16Vec3::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I16Vec3::MIN.checked_sub_unsigned(U16Vec3::ONE), None);
+        assert_eq!(
+            I16Vec3::ZERO.checked_sub_unsigned(U16Vec3::ONE),
+            Some(I16Vec3::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I16Vec3::new(i16::MAX, i16::MAX, i16::MAX).wrapping_add_unsigned(U16Vec3::new(1, 1, 1)),
@@ -2629,6 +2734,22 @@ mod ivec3 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(IVec3::MAX.checked_add_unsigned(UVec3::ONE), None);
+        assert_eq!(
+            IVec3::NEG_ONE.checked_add_unsigned(UVec3::ONE),
+            Some(IVec3::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(IVec3::MIN.checked_sub_unsigned(UVec3::ONE), None);
+        assert_eq!(
+            IVec3::ZERO.checked_sub_unsigned(UVec3::ONE),
+            Some(IVec3::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             IVec3::new(i32::MAX, i32::MAX, i32::MAX).wrapping_add_unsigned(UVec3::new(1, 1, 1)),
@@ -2840,6 +2961,22 @@ mod i64vec3 {
         assert!(I64Vec3::try_from(U64Vec3::new(1, 2, u64::MAX)).is_err());
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I64Vec3::MAX.checked_add_unsigned(U64Vec3::ONE), None);
+        assert_eq!(
+            I64Vec3::NEG_ONE.checked_add_unsigned(U64Vec3::ONE),
+            Some(I64Vec3::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I64Vec3::MIN.checked_sub_unsigned(U64Vec3::ONE), None);
+        assert_eq!(
+            I64Vec3::ZERO.checked_sub_unsigned(U64Vec3::ONE),
+            Some(I64Vec3::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I64Vec3::new(i64::MAX, i64::MAX, i64::MAX).wrapping_add_unsigned(U64Vec3::new(1, 1, 1)),
diff --git a/tests/vec4.rs b/tests/vec4.rs
index 7522751..e8d0212 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -968,6 +968,49 @@ macro_rules! impl_vec4_signed_integer_tests {
             assert_eq!((-$vec4::ONE).signum(), -$vec4::ONE);
         });
 
+        glam_test!(test_checked_add, {
+            assert_eq!($vec4::MAX.checked_add($vec4::ONE), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::X), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::Y), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::Z), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::W), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::ZERO), Some($vec4::MAX));
+        });
+
+        glam_test!(test_checked_sub, {
+            assert_eq!($vec4::MIN.checked_sub($vec4::ONE), None);
+            assert_eq!($vec4::MIN.checked_sub($vec4::X), None);
+            assert_eq!($vec4::MIN.checked_sub($vec4::Y), None);
+            assert_eq!($vec4::MIN.checked_sub($vec4::Z), None);
+            assert_eq!($vec4::MIN.checked_sub($vec4::W), None);
+            assert_eq!($vec4::MIN.checked_sub($vec4::ZERO), Some($vec4::MIN));
+        });
+
+        glam_test!(test_checked_mul, {
+            assert_eq!($vec4::MIN.checked_mul($vec4::MIN), None);
+            assert_eq!($vec4::MAX.checked_mul($vec4::MIN), None);
+            assert_eq!($vec4::MIN.checked_mul($vec4::MAX), None);
+            assert_eq!($vec4::MAX.checked_mul($vec4::MAX), None);
+            assert_eq!($vec4::ZERO.checked_mul($vec4::MIN), Some($vec4::ZERO));
+            assert_eq!($vec4::MAX.checked_mul($vec4::ZERO), Some($vec4::ZERO));
+            assert_eq!($vec4::MIN.checked_mul($vec4::ONE), Some($vec4::MIN));
+            assert_eq!($vec4::MAX.checked_mul($vec4::ONE), Some($vec4::MAX));
+            assert_eq!($vec4::ZERO.checked_mul($vec4::ZERO), Some($vec4::ZERO));
+            assert_eq!($vec4::ONE.checked_mul($vec4::ONE), Some($vec4::ONE));
+        });
+
+        glam_test!(test_checked_div, {
+            assert_eq!($vec4::MIN.checked_div($vec4::ZERO), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::ZERO), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::X), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::Y), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::Z), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::W), None);
+            assert_eq!($vec4::ZERO.checked_div($vec4::ONE), Some($vec4::ZERO));
+            assert_eq!($vec4::MIN.checked_div($vec4::ONE), Some($vec4::MIN));
+            assert_eq!($vec4::MAX.checked_div($vec4::ONE), Some($vec4::MAX));
+        });
+
         glam_test!(test_manhattan_distance, {
             assert_eq!(
                 $vec4::new(41, 8, 21, 87).manhattan_distance($vec4::new(49, 48, 28, 40)),
@@ -1025,6 +1068,42 @@ macro_rules! impl_vec4_unsigned_integer_tests {
     ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident, $masknew:ident) => {
         impl_vec4_tests!($t, $new, $vec4, $vec3, $vec2, $mask, $masknew);
 
+        glam_test!(test_checked_add, {
+            assert_eq!($vec4::MAX.checked_add($vec4::ONE), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::X), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::Y), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::Z), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::W), None);
+            assert_eq!($vec4::MAX.checked_add($vec4::ZERO), Some($vec4::MAX));
+        });
+
+        glam_test!(test_checked_sub, {
+            assert_eq!($vec4::ZERO.checked_sub($vec4::ONE), None);
+            assert_eq!($vec4::ZERO.checked_sub($vec4::X), None);
+            assert_eq!($vec4::ZERO.checked_sub($vec4::Y), None);
+            assert_eq!($vec4::ZERO.checked_sub($vec4::Z), None);
+            assert_eq!($vec4::ZERO.checked_sub($vec4::W), None);
+            assert_eq!($vec4::ZERO.checked_sub($vec4::ZERO), Some($vec4::MIN));
+        });
+
+        glam_test!(test_checked_mul, {
+            assert_eq!($vec4::MAX.checked_mul($vec4::MAX), None);
+            assert_eq!($vec4::MAX.checked_mul($vec4::ZERO), Some($vec4::ZERO));
+            assert_eq!($vec4::MAX.checked_mul($vec4::ONE), Some($vec4::MAX));
+            assert_eq!($vec4::ZERO.checked_mul($vec4::ZERO), Some($vec4::ZERO));
+            assert_eq!($vec4::ONE.checked_mul($vec4::ONE), Some($vec4::ONE));
+        });
+
+        glam_test!(test_checked_div, {
+            assert_eq!($vec4::MAX.checked_div($vec4::ZERO), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::X), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::Y), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::Z), None);
+            assert_eq!($vec4::MAX.checked_div($vec4::W), None);
+            assert_eq!($vec4::ZERO.checked_div($vec4::ONE), Some($vec4::ZERO));
+            assert_eq!($vec4::MAX.checked_div($vec4::ONE), Some($vec4::MAX));
+        });
+
         glam_test!(test_manhattan_distance, {
             assert_eq!(
                 $vec4::new(41, 8, 21, 87).manhattan_distance($vec4::new(49, 48, 128, 40)),
@@ -2210,6 +2289,22 @@ mod i8vec4 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I8Vec4::MAX.checked_add_unsigned(U8Vec4::ONE), None);
+        assert_eq!(
+            I8Vec4::NEG_ONE.checked_add_unsigned(U8Vec4::ONE),
+            Some(I8Vec4::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I8Vec4::MIN.checked_sub_unsigned(U8Vec4::ONE), None);
+        assert_eq!(
+            I8Vec4::ZERO.checked_sub_unsigned(U8Vec4::ONE),
+            Some(I8Vec4::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I8Vec4::new(i8::MAX, i8::MAX, i8::MAX, i8::MAX)
@@ -2556,6 +2651,22 @@ mod i16vec4 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I16Vec4::MAX.checked_add_unsigned(U16Vec4::ONE), None);
+        assert_eq!(
+            I16Vec4::NEG_ONE.checked_add_unsigned(U16Vec4::ONE),
+            Some(I16Vec4::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I16Vec4::MIN.checked_sub_unsigned(U16Vec4::ONE), None);
+        assert_eq!(
+            I16Vec4::ZERO.checked_sub_unsigned(U16Vec4::ONE),
+            Some(I16Vec4::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I16Vec4::new(i16::MAX, i16::MAX, i16::MAX, i16::MAX)
@@ -2885,6 +2996,22 @@ mod ivec4 {
         );
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(IVec4::MAX.checked_add_unsigned(UVec4::ONE), None);
+        assert_eq!(
+            IVec4::NEG_ONE.checked_add_unsigned(UVec4::ONE),
+            Some(IVec4::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(IVec4::MIN.checked_sub_unsigned(UVec4::ONE), None);
+        assert_eq!(
+            IVec4::ZERO.checked_sub_unsigned(UVec4::ONE),
+            Some(IVec4::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             IVec4::new(i32::MAX, i32::MAX, i32::MAX, i32::MAX)
@@ -3138,6 +3265,22 @@ mod i64vec4 {
         assert!(I64Vec4::try_from(U64Vec4::new(1, 2, 3, u64::MAX)).is_err());
     });
 
+    glam_test!(test_checked_add_unsigned, {
+        assert_eq!(I64Vec4::MAX.checked_add_unsigned(U64Vec4::ONE), None);
+        assert_eq!(
+            I64Vec4::NEG_ONE.checked_add_unsigned(U64Vec4::ONE),
+            Some(I64Vec4::ZERO)
+        );
+    });
+
+    glam_test!(test_checked_sub_unsigned, {
+        assert_eq!(I64Vec4::MIN.checked_sub_unsigned(U64Vec4::ONE), None);
+        assert_eq!(
+            I64Vec4::ZERO.checked_sub_unsigned(U64Vec4::ONE),
+            Some(I64Vec4::NEG_ONE)
+        );
+    });
+
     glam_test!(test_wrapping_add_unsigned, {
         assert_eq!(
             I64Vec4::new(i64::MAX, i64::MAX, i64::MAX, i64::MAX)