From 0eac0567ce73075fdc5eb98cca9ac36074334270 Mon Sep 17 00:00:00 2001 From: Simon Ask Ulsnes Date: Thu, 8 May 2025 07:44:00 +0200 Subject: [PATCH 1/5] Alignment fixes (soundness) --- CHANGELOG.md | 17 ++ Cargo.toml | 2 +- README.md | 2 +- src/angle.rs | 8 +- src/bindings/vec.rs | 2 + src/forward.rs | 4 +- src/impl_ops.rs | 16 +- src/impl_traits.rs | 39 +---- src/impl_vectorlike.rs | 15 -- src/lib.rs | 2 +- src/matrix.rs | 40 ++--- src/point.rs | 10 +- src/size.rs | 4 +- src/traits/transparent.rs | 54 ++----- src/transform.rs | 4 +- src/vector.rs | 99 ++++++------ tests/compatibility.rs | 321 +------------------------------------ tests/static_assertions.rs | 31 ---- 18 files changed, 139 insertions(+), 531 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57a8418..87a2bb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixes + +- Fixed a soundness hole in `Vector4` when using smaller scalar types. + +### Breaking changes + +- Vector types and references can no longer be converted to and from `glam` + types by reference. This fixes a soundness hole, because it relaxes the + alignment requirement of `Vector4`, which would otherwise result in a size + mismatch between `Vector4` and `glam` vectors for smaller scalar types. I.e. + `glam::U8Vec4` has alignment 1. In general, it is brittle to rely on the + specific alignment of `glam` vector types, because they are highly + architecture dependent, and it is unlikely that it gains anything, because + unaligned vector register loads are no longer slow. + ## [0.17.0] - 2025-05-03 ### Added diff --git a/Cargo.toml b/Cargo.toml index 2a4d9e0..99d5510 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ glam = { version = "0.30.0", default-features = false, features = [ "bytemuck", "approx", ] } -bytemuck = { version = "^1.8", default-features = false } +bytemuck = { version = "^1.23", default-features = false, features = ["must_cast"] } num-traits = { version = "^0.2.19", default-features = false } approx = "^0.5" facet = { version = "0.18.4", optional = true, default-features = false } diff --git a/README.md b/README.md index e023e67..90a9692 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ let size: Size2 = Size2 { width: 100.0, height: 200.0 }; let vector_untyped: &Vector4 = vector.as_untyped(); // Use glam when needed: -let vector_raw: &glam::Vec4 = glamour::Transparent::peel_ref(&vector); +let vector_raw: glam::Vec4 = vector.to_raw(); ``` [See the documentation module for more examples.](crate::docs::examples) diff --git a/src/angle.rs b/src/angle.rs index d34e693..8d3f1dd 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -31,7 +31,7 @@ pub struct Angle { } unsafe impl Zeroable for Angle {} unsafe impl Pod for Angle {} -unsafe impl Transparent for Angle { +impl Transparent for Angle { type Wrapped = T; } @@ -432,8 +432,6 @@ mod tests { assert_ulps_eq, assert_ulps_ne, }; - use crate::{peel_mut, peel_ref}; - use super::*; type Angle = super::Angle; @@ -517,9 +515,7 @@ mod tests { #[test] fn angle_cast() { - let mut a = Angle::CIRCLE; - let _: &f32 = peel_ref(&a); - let _: &mut f32 = peel_mut(&mut a); + let a = Angle::CIRCLE; let _: f32 = peel(a); let _: f32 = a.to_radians(); let _: Angle = 1.0.into(); diff --git a/src/bindings/vec.rs b/src/bindings/vec.rs index c81a2ac..13dd774 100644 --- a/src/bindings/vec.rs +++ b/src/bindings/vec.rs @@ -26,6 +26,8 @@ pub trait Vector: + DivAssign + Rem + RemAssign + + core::iter::Sum + + core::iter::Product + for<'a> core::iter::Sum<&'a Self> + for<'a> core::iter::Product<&'a Self> { diff --git a/src/forward.rs b/src/forward.rs index 10b13a9..fdcd976 100644 --- a/src/forward.rs +++ b/src/forward.rs @@ -179,7 +179,7 @@ macro_rules! forward_fn_self_ref { { crate::wrap_ret_val!( $($($ret)* => )* - crate::peel_ref(self).$fn_name( + crate::peel_copy(self).$fn_name( $(crate::forward_arg!($arg_name: $arg_ty)),* ) ) @@ -436,7 +436,7 @@ macro_rules! forward_arg { crate::peel($arg) }; ($arg:ident: ref_self) => { - crate::peel_ref($arg) + &crate::peel_copy($arg) }; ($arg:ident: ref_scalar_array_4) => { $arg diff --git a/src/impl_ops.rs b/src/impl_ops.rs index d63bcde..15696d1 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -252,12 +252,16 @@ macro_rules! impl_assign_ops { $( impl core::ops::$op_trait<$rhs_ty> for $lhs_ty { fn $op_name(&mut self, rhs: $rhs_ty) { - core::ops::$op_trait::$op_name(crate::peel_mut(self), crate::peel(rhs)) + let mut value = crate::peel_copy(self); + core::ops::$op_trait::$op_name(&mut value, crate::peel(rhs)); + *self = crate::wrap(value); } } impl core::ops::$op_trait<&$rhs_ty> for $lhs_ty { fn $op_name(&mut self, rhs: &$rhs_ty) { - core::ops::$op_trait::$op_name(crate::peel_mut(self), crate::peel(*rhs)) + let mut value = crate::peel_copy(self); + core::ops::$op_trait::$op_name(&mut value, crate::peel(*rhs)); + *self = crate::wrap(value); } } )* @@ -275,12 +279,16 @@ macro_rules! impl_scalar_assign_ops { $( impl> core::ops::$op_trait<$rhs_ty> for $lhs_ty { fn $op_name(&mut self, rhs: $rhs_ty) { - core::ops::$op_trait::$op_name(crate::peel_mut(self), rhs); + let mut value = crate::peel_copy(self); + core::ops::$op_trait::$op_name(&mut value, rhs); + *self = crate::wrap(value); } } impl> core::ops::$op_trait<&$rhs_ty> for $lhs_ty { fn $op_name(&mut self, rhs: &$rhs_ty) { - core::ops::$op_trait::$op_name(crate::peel_mut(self), *rhs); + let mut value = crate::peel_copy(self); + core::ops::$op_trait::$op_name(&mut value, *rhs); + *self = crate::wrap(value); } } )* diff --git a/src/impl_traits.rs b/src/impl_traits.rs index d7364a6..ad76e5e 100644 --- a/src/impl_traits.rs +++ b/src/impl_traits.rs @@ -13,7 +13,7 @@ macro_rules! impl_basic_traits { impl PartialEq for $base_type_name { fn eq(&self, other: &Self) -> bool { - *crate::peel_ref(self) == *crate::peel_ref(other) + crate::peel_copy(self) == crate::peel_copy(other) } } @@ -76,7 +76,7 @@ macro_rules! impl_basic_traits_vectorlike { where H: core::hash::Hasher, { - core::hash::Hash::hash(crate::peel_ref(self), state) + core::hash::Hash::hash(&crate::peel_copy(self), state) } } @@ -132,12 +132,12 @@ macro_rules! impl_basic_traits_vectorlike { #[must_use] fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - crate::peel_ref(self).abs_diff_eq(crate::peel_ref(other), epsilon) + crate::peel_copy(self).abs_diff_eq(&crate::peel_copy(other), epsilon) } #[must_use] fn abs_diff_ne(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - crate::peel_ref(self).abs_diff_ne(crate::peel_ref(other), epsilon) + crate::peel_copy(self).abs_diff_ne(&crate::peel_copy(other), epsilon) } } @@ -154,7 +154,7 @@ macro_rules! impl_basic_traits_vectorlike { epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - crate::peel_ref(self).relative_eq(crate::peel_ref(other), epsilon, max_relative) + crate::peel_copy(self).relative_eq(&crate::peel_copy(other), epsilon, max_relative) } #[must_use] @@ -164,7 +164,7 @@ macro_rules! impl_basic_traits_vectorlike { epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - crate::peel_ref(self).relative_ne(crate::peel_ref(other), epsilon, max_relative) + crate::peel_copy(self).relative_ne(&crate::peel_copy(other), epsilon, max_relative) } } @@ -176,12 +176,12 @@ macro_rules! impl_basic_traits_vectorlike { #[must_use] fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - crate::peel_ref(self).ulps_eq(crate::peel_ref(other), epsilon, max_ulps) + crate::peel_copy(self).ulps_eq(&crate::peel_copy(other), epsilon, max_ulps) } #[must_use] fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - crate::peel_ref(self).ulps_ne(crate::peel_ref(other), epsilon, max_ulps) + crate::peel_copy(self).ulps_ne(&crate::peel_copy(other), epsilon, max_ulps) } } @@ -283,29 +283,6 @@ macro_rules! impl_basic_traits_vectorlike { crate::peel(value) } } - impl> core::borrow::Borrow<$glam_ty> for $base_type_name - { - fn borrow(&self) -> &$glam_ty { - crate::peel_ref(self) - } - } - impl> core::borrow::BorrowMut<$glam_ty> - for $base_type_name - { - fn borrow_mut(&mut self) -> &mut $glam_ty { - crate::peel_mut(self) - } - } - impl> AsRef<$glam_ty> for $base_type_name { - fn as_ref(&self) -> &$glam_ty { - crate::peel_ref(self) - } - } - impl> AsMut<$glam_ty> for $base_type_name { - fn as_mut(&mut self) -> &mut $glam_ty { - crate::peel_mut(self) - } - } )* }; } diff --git a/src/impl_vectorlike.rs b/src/impl_vectorlike.rs index 8a903b3..3213bc7 100644 --- a/src/impl_vectorlike.rs +++ b/src/impl_vectorlike.rs @@ -48,11 +48,6 @@ macro_rules! simdlike { /// The unit axes. pub const AXES: [Self; 2] = [Self::X, Self::Y]; - /// Transparently cast this type to its underlying, bitwise compatible `glam` type. - #[inline(always)] - pub fn as_raw(&self) -> &::Vec2 { - crate::Transparent::peel_ref(self) - } /// Transparently cast this type to its underlying, bitwise compatible `glam` type. #[inline(always)] pub fn to_raw(self) -> ::Vec2 { @@ -133,11 +128,6 @@ macro_rules! simdlike { /// The unit axes. pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z]; - /// Transparently cast this type to its underlying, bitwise compatible `glam` type. - #[inline(always)] - pub fn as_raw(&self) -> &::Vec3 { - crate::Transparent::peel_ref(self) - } /// Transparently cast this type to its underlying, bitwise compatible `glam` type. #[inline(always)] pub fn to_raw(self) -> ::Vec3 { @@ -242,11 +232,6 @@ macro_rules! simdlike { /// The unit axes. pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W]; - /// Transparently cast this type to its underlying, bitwise compatible `glam` type. - #[inline(always)] - pub fn as_raw(&self) -> &::Vec4 { - crate::Transparent::peel_ref(self) - } /// Transparently cast this type to its underlying, bitwise compatible `glam` type. #[inline(always)] pub fn to_raw(self) -> ::Vec4 { diff --git a/src/lib.rs b/src/lib.rs index e5b37f6..63337c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,7 @@ mod interfaces; #[doc(no_inline)] pub use traits::{Contains, Intersection, Transparent, Union}; #[doc(hidden)] -pub use traits::{peel, peel_mut, peel_ref, rewrap, wrap}; +pub use traits::{peel, peel_copy, rewrap, wrap}; /// Convenience glob import. /// diff --git a/src/matrix.rs b/src/matrix.rs index 40f8168..151e3a6 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -9,7 +9,7 @@ use core::ops::{Div, DivAssign, Mul, MulAssign}; use crate::{ Point2, Scalar, Transparent, Unit, Vector2, Vector3, Vector4, bindings::{Matrix, Matrix2 as SimdMatrix2, Matrix3 as SimdMatrix3, Matrix4 as SimdMatrix4}, - peel, peel_ref, + peel, peel_copy, prelude::*, scalar::FloatScalar, unit::FloatUnit, @@ -33,7 +33,7 @@ pub struct Matrix2(Vector4); unsafe impl Zeroable for Matrix2 {} unsafe impl Pod for Matrix2 {} // SAFETY: This is the fundamental guarantee of this crate. -unsafe impl Transparent for Matrix2 { +impl Transparent for Matrix2 { type Wrapped = T::Mat2; } @@ -79,7 +79,7 @@ pub struct Matrix3 { unsafe impl Zeroable for Matrix3 {} unsafe impl Pod for Matrix3 {} // SAFETY: This is the fundamental guarantee of this crate. -unsafe impl Transparent for Matrix3 { +impl Transparent for Matrix3 { type Wrapped = T::Mat3; } @@ -130,7 +130,7 @@ pub struct Matrix4 { unsafe impl Zeroable for Matrix4 {} unsafe impl Pod for Matrix4 {} // SAFETY: This is the fundamental guarantee of this crate. -unsafe impl Transparent for Matrix4 { +impl Transparent for Matrix4 { type Wrapped = T::Mat4; } @@ -708,11 +708,11 @@ where } fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - peel_ref(self).abs_diff_eq(peel_ref(other), epsilon) + peel_copy(self).abs_diff_eq(&peel_copy(other), epsilon) } fn abs_diff_ne(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - peel_ref(self).abs_diff_ne(peel_ref(other), epsilon) + peel_copy(self).abs_diff_ne(&peel_copy(other), epsilon) } } @@ -731,7 +731,7 @@ where epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - peel_ref(self).relative_eq(peel_ref(other), epsilon, max_relative) + peel_copy(self).relative_eq(&peel_copy(other), epsilon, max_relative) } fn relative_ne( @@ -740,7 +740,7 @@ where epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - peel_ref(self).relative_ne(peel_ref(other), epsilon, max_relative) + peel_copy(self).relative_ne(&peel_copy(other), epsilon, max_relative) } } @@ -750,11 +750,11 @@ impl UlpsEq for Matrix2 { } fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - peel_ref(self).ulps_eq(peel_ref(other), epsilon, max_ulps) + peel_copy(self).ulps_eq(&peel_copy(other), epsilon, max_ulps) } fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - peel_ref(self).ulps_ne(peel_ref(other), epsilon, max_ulps) + peel_copy(self).ulps_ne(&peel_copy(other), epsilon, max_ulps) } } @@ -793,7 +793,7 @@ where epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - peel_ref(self).relative_eq(peel_ref(other), epsilon, max_relative) + peel_copy(self).relative_eq(&peel_copy(other), epsilon, max_relative) } fn relative_ne( @@ -802,7 +802,7 @@ where epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - peel_ref(self).relative_ne(peel_ref(other), epsilon, max_relative) + peel_copy(self).relative_ne(&peel_copy(other), epsilon, max_relative) } } @@ -812,11 +812,11 @@ impl UlpsEq for Matrix3 { } fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - peel_ref(self).ulps_eq(peel_ref(other), epsilon, max_ulps) + peel_copy(self).ulps_eq(&peel_copy(other), epsilon, max_ulps) } fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - peel_ref(self).ulps_ne(peel_ref(other), epsilon, max_ulps) + peel_copy(self).ulps_ne(&peel_copy(other), epsilon, max_ulps) } } @@ -832,11 +832,11 @@ where } fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - peel_ref(self).abs_diff_eq(peel_ref(other), epsilon) + peel_copy(self).abs_diff_eq(&peel_copy(other), epsilon) } fn abs_diff_ne(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - peel_ref(self).abs_diff_ne(peel_ref(other), epsilon) + peel_copy(self).abs_diff_ne(&peel_copy(other), epsilon) } } @@ -851,7 +851,7 @@ impl RelativeEq for Matrix4 { epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - peel_ref(self).relative_eq(peel_ref(other), epsilon, max_relative) + peel_copy(self).relative_eq(&peel_copy(other), epsilon, max_relative) } fn relative_ne( @@ -860,7 +860,7 @@ impl RelativeEq for Matrix4 { epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - peel_ref(self).relative_ne(peel_ref(other), epsilon, max_relative) + peel_copy(self).relative_ne(&peel_copy(other), epsilon, max_relative) } } @@ -874,11 +874,11 @@ where } fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - peel_ref(self).ulps_eq(peel_ref(other), epsilon, max_ulps) + peel_copy(self).ulps_eq(&peel_copy(other), epsilon, max_ulps) } fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - peel_ref(self).ulps_ne(peel_ref(other), epsilon, max_ulps) + peel_copy(self).ulps_ne(&peel_copy(other), epsilon, max_ulps) } } diff --git a/src/point.rs b/src/point.rs index 0b5abf9..43d0ca9 100644 --- a/src/point.rs +++ b/src/point.rs @@ -47,7 +47,7 @@ unsafe impl Zeroable for Point2 {} // SAFETY: `T::Scalar` is `Pod`. unsafe impl Pod for Point2 {} // SAFETY: This is the fundamental guarantee of this crate. -unsafe impl Transparent for Point2 { +impl Transparent for Point2 { type Wrapped = ::Vec2; } @@ -82,7 +82,7 @@ pub struct Point3 { unsafe impl Zeroable for Point3 {} /// SAFETY: `T::Scalar` is `Pod`. unsafe impl Pod for Point3 {} -unsafe impl Transparent for Point3 { +impl Transparent for Point3 { type Wrapped = ::Vec3; } @@ -93,8 +93,8 @@ unsafe impl Transparent for Point3 { /// which means that reference-casting from those glam types to `Point4` type /// will fail (but not the other way around). #[cfg_attr( - not(any(feature = "scalar-math", target_arch = "spirv")), - repr(C, align(16)) + not(target_arch = "spirv"), + repr(C) )] #[cfg_attr( all(not(target_arch = "wasm32"), feature = "wasmtime"), @@ -123,7 +123,7 @@ pub struct Point4 { unsafe impl Zeroable for Point4 {} /// SAFETY: `T::Scalar` is `Pod`. unsafe impl Pod for Point4 {} -unsafe impl Transparent for Point4 { +impl Transparent for Point4 { type Wrapped = ::Vec4; } diff --git a/src/size.rs b/src/size.rs index f15bec7..ec47aa4 100644 --- a/src/size.rs +++ b/src/size.rs @@ -34,7 +34,7 @@ pub struct Size2 { unsafe impl Pod for Size2 {} /// SAFETY: All members are `Pod`, and we are `#[repr(C)]`. unsafe impl Zeroable for Size2 {} -unsafe impl Transparent for Size2 { +impl Transparent for Size2 { type Wrapped = ::Vec2; } @@ -67,7 +67,7 @@ unsafe impl Pod for Size3 {} /// SAFETY: All members are `Pod`, and we are `#[repr(C)]`. unsafe impl Zeroable for Size3 {} // SAFETY: This is the guarantee of this crate. -unsafe impl Transparent for Size3 { +impl Transparent for Size3 { type Wrapped = ::Vec3; } diff --git a/src/traits/transparent.rs b/src/traits/transparent.rs index 6b3e8f5..a46c3a1 100644 --- a/src/traits/transparent.rs +++ b/src/traits/transparent.rs @@ -1,5 +1,3 @@ -use core::mem::{align_of, size_of, transmute_copy}; - use bytemuck::Pod; /// One-way `TransparentWrapper`. @@ -9,54 +7,30 @@ use bytemuck::Pod; /// This is similar to `bytemuck::TransparentWrapper`, except that it only requires that references can be converted /// **to** `T`, and not the other way around. In other words, the alignment of `Self` and `T` do not need to be equal, /// but rather `align_of::() >= align_of::()`. -pub unsafe trait Transparent: Pod { +pub trait Transparent: Pod { /// The inner type that shares a compatible representation with `Self`. type Wrapped: Pod; /// Wrap the inner type by copy. /// /// This is a no-op in most cases, except it may re-align the object if the alignment of `T` is higher. + #[inline(always)] fn wrap(x: Self::Wrapped) -> Self { - const { - assert!(size_of::() == size_of::()); - } - - unsafe { transmute_copy(&x) } + bytemuck::must_cast(x) } /// Unwrap the inner type by copy. /// /// This is a no-op in most cases, except it may re-align the object if the alignment of `T` is higher. fn peel(x: Self) -> Self::Wrapped { - const { - assert!(size_of::() == size_of::()); - } - - unsafe { transmute_copy(&x) } + bytemuck::must_cast(x) } /// Convert a reference to the inner type. /// /// This asserts at compile time that the alignmen of `T` is less than or equal to the alignment of `Self`. - fn peel_ref(x: &Self) -> &Self::Wrapped { - const { - assert!(size_of::() == size_of::()); - assert!(align_of::() <= align_of::()); - } - - unsafe { &*core::ptr::from_ref::(x).cast() } - } - - /// Convert a mutable reference to the inner type. - /// - /// This asserts at compile time that the alignmen of `T` is less than or equal to the alignment of `Self`. - fn peel_mut(x: &mut Self) -> &mut Self::Wrapped { - const { - assert!(size_of::() == size_of::()); - assert!(align_of::() <= align_of::()); - } - - unsafe { &mut *core::ptr::from_mut::(x).cast() } + fn peel_copy(x: &Self) -> Self::Wrapped { + bytemuck::must_cast(*x) } } @@ -69,12 +43,8 @@ pub fn peel(a: T) -> T::Wrapped { Transparent::peel(a) } /// Convenience function for calling [`Transparent::peel_ref()`]. -pub fn peel_ref(a: &T) -> &T::Wrapped { - Transparent::peel_ref(a) -} -/// Convenience function for calling [`Transparent::peel_mut()`]. -pub fn peel_mut(a: &mut T) -> &mut T::Wrapped { - Transparent::peel_mut(a) +pub fn peel_copy(a: &T) -> T::Wrapped { + Transparent::peel_copy(a) } /// Convenience function for calling [`Transparent::peel()`] and [`Transparent::wrap()`]. pub fn rewrap>(a: A) -> B { @@ -96,7 +66,7 @@ mod tests { } unsafe impl Zeroable for Bigger {} unsafe impl Pod for Bigger {} - unsafe impl Transparent for Bigger { + impl Transparent for Bigger { type Wrapped = Overaligned; } @@ -110,7 +80,7 @@ mod tests { } unsafe impl Zeroable for Overaligned {} unsafe impl Pod for Overaligned {} - unsafe impl Transparent for Overaligned { + impl Transparent for Overaligned { type Wrapped = Bigger; } @@ -127,8 +97,6 @@ mod tests { let overaligned: Overaligned = Transparent::peel(bigger); assert_eq!(bigger.a, 1); assert_eq!(overaligned.a, 1); - let _bigger: &Bigger = Transparent::peel_ref(&overaligned); - // This should fail to compile: - // let overaligned: &Overaligned = Transparent::peel_ref(bigger); + let _bigger: Bigger = Transparent::peel_copy(&overaligned); } } diff --git a/src/transform.rs b/src/transform.rs index 5359ebd..236330a 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -249,10 +249,10 @@ unsafe impl Zeroable for Transform2 {} unsafe impl Pod for Transform2 {} unsafe impl Zeroable for Transform3 {} unsafe impl Pod for Transform3 {} -unsafe impl Transparent for Transform2 { +impl Transparent for Transform2 { type Wrapped = Matrix3; } -unsafe impl Transparent for Transform3 { +impl Transparent for Transform3 { type Wrapped = Matrix4; } diff --git a/src/vector.rs b/src/vector.rs index 536da2d..3006899 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -17,7 +17,7 @@ use num_traits::identities::{ConstOne, ConstZero}; use crate::scalar::FloatScalar; use crate::unit::FloatUnit; use crate::{Point2, Point3, Point4, Scalar, Size2, Size3, Unit, bindings::prelude::*}; -use crate::{Transparent, peel, peel_ref, wrap}; +use crate::{Transparent, peel, peel_copy, wrap}; /// Vector swizzling by const generics. /// @@ -73,14 +73,13 @@ unsafe impl Zeroable for Vector2 {} /// SAFETY: `T::Scalar` is `Pod`. unsafe impl Pod for Vector2 {} /// SAFETY: These are guaranteed to have the same representation. -unsafe impl Transparent for Vector2 { +impl Transparent for Vector2 { type Wrapped = ::Vec2; } /// 3D vector. /// -/// Alignment: Same as the scalar (so not 16 bytes). If you really need 16-byte -/// alignment, use [`Vector4`]. +/// Alignment: Same as the scalar (so not 16 bytes). #[cfg_attr( all(not(target_arch = "wasm32"), feature = "wasmtime"), derive( @@ -109,7 +108,7 @@ unsafe impl Zeroable for Vector3 {} /// SAFETY: `T::Scalar` is `Pod`. unsafe impl Pod for Vector3 {} /// SAFETY: These are guaranteed to have the same representation. -unsafe impl Transparent for Vector3 { +impl Transparent for Vector3 { type Wrapped = ::Vec3; } @@ -117,14 +116,12 @@ unsafe impl Transparent for Vector3 { /// /// # Alignment /// -/// This is always 16-byte aligned. [`glam::DVec4`] is only 8-byte aligned (for some reason), and integer vectors are -/// only 4-byte aligned, which means that reference-casting from those glam types to `Vector4` type will fail (but not -/// the other way around - see [`Vector4::as_raw()`]). -/// -/// This also means that smaller integer types (i16 etc.) will be over-aligned, consuming much more memory. +/// This is always has the same alignment as the scalar component type, and +/// _not_ the "normal" 128-bit alignment. This is due to limitations in the +/// `#[repr(align(...))]` attribute when combined with generics. #[cfg_attr( - not(any(feature = "scalar-math", target_arch = "spirv")), - repr(C, align(16)) + not(target_arch = "spirv"), + repr(C) )] #[cfg_attr( all(not(target_arch = "wasm32"), feature = "wasmtime"), @@ -155,7 +152,7 @@ unsafe impl Zeroable for Vector4 {} /// SAFETY: `T::Scalar` is `Pod`. unsafe impl Pod for Vector4 {} /// SAFETY: These are guaranteed to have the same representation. -unsafe impl Transparent for Vector4 { +impl Transparent for Vector4 { type Wrapped = ::Vec4; } @@ -324,13 +321,33 @@ where } } +impl Sum for Vector2 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + wrap(iter.map(peel).sum()) + } +} + impl<'a, T: Unit> Sum<&'a Vector2> for Vector2 { #[inline] fn sum(iter: I) -> Self where I: Iterator, { - wrap(iter.map(peel_ref).sum()) + iter.copied().sum() + } +} + +impl Sum> for Vector3 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + wrap(iter.map(peel).sum()) } } @@ -340,7 +357,17 @@ impl<'a, T: Unit> Sum<&'a Vector3> for Vector3 { where I: Iterator, { - wrap(iter.map(peel_ref).sum()) + iter.copied().sum() + } +} + +impl Sum for Vector4 { + #[inline] + fn sum(iter: I) -> Self + where + I: Iterator, + { + wrap(iter.map(peel).sum()) } } @@ -350,7 +377,7 @@ impl<'a, T: Unit> Sum<&'a Vector4> for Vector4 { where I: Iterator, { - wrap(iter.map(peel_ref).sum()) + iter.copied().sum() } } @@ -360,7 +387,7 @@ impl<'a, T: Unit> Product<&'a Vector2> for Vector2 { where I: Iterator, { - wrap(iter.map(peel_ref).product()) + wrap(iter.map(peel_copy).product()) } } @@ -370,7 +397,7 @@ impl<'a, T: Unit> Product<&'a Vector3> for Vector3 { where I: Iterator, { - wrap(iter.map(peel_ref).product()) + wrap(iter.map(peel_copy).product()) } } @@ -380,7 +407,7 @@ impl<'a, T: Unit> Product<&'a Vector4> for Vector4 { where I: Iterator, { - wrap(iter.map(peel_ref).product()) + wrap(iter.map(peel_copy).product()) } } @@ -415,7 +442,6 @@ impl core::fmt::Debug for Vector4 { #[cfg(test)] mod tests { use approx::{RelativeEq, UlpsEq, assert_abs_diff_eq}; - use core::ptr; use crate::{Angle, AngleConsts, vec2, vec3, vec4, vector}; @@ -1131,45 +1157,18 @@ mod tests { ); } - #[test] - fn glam_reference_conversion() { - use core::borrow::{Borrow, BorrowMut}; - - let mut vec = Vector4::::new(1, 2, 3, 4); - - let vec1: &glam::IVec4 = vec.as_ref(); - assert_eq!(*vec1, glam::IVec4::new(1, 2, 3, 4)); - - let vec1: &glam::IVec4 = vec.as_raw(); - assert_eq!(*vec1, glam::IVec4::new(1, 2, 3, 4)); - - let vec2: &mut glam::IVec4 = vec.as_mut(); - vec2.y = 100; - assert_eq!(vec, vec4![1, 100, 3, 4]); - - let vec3: &glam::IVec4 = vec.borrow(); - assert_eq!(*vec3, glam::IVec4::new(1, 100, 3, 4)); - - let vec4: &mut glam::IVec4 = vec.borrow_mut(); - vec4.z = 100; - assert_eq!(*vec4, glam::IVec4::new(1, 100, 100, 4)); - } - #[test] fn glam_raw_conversion() { let v2 = Vector2::::new(1.0, 2.0); let v3 = Vector3::::new(1.0, 2.0, 3.0); let v4 = Vector4::::new(1.0, 2.0, 3.0, 4.0); - assert!(ptr::eq(v2.as_raw(), peel_ref(&v2))); assert_eq!(v2.to_raw(), glam::Vec2::new(1.0, 2.0)); assert_eq!(v2, Vector2::from_raw(glam::Vec2::new(1.0, 2.0))); - assert!(ptr::eq(v3.as_raw(), peel_ref(&v3))); assert_eq!(v3.to_raw(), glam::Vec3::new(1.0, 2.0, 3.0)); assert_eq!(v3, Vector3::from_raw(glam::Vec3::new(1.0, 2.0, 3.0))); - assert!(ptr::eq(v4.as_raw(), peel_ref(&v4))); assert_eq!(v4.to_raw(), glam::Vec4::new(1.0, 2.0, 3.0, 4.0)); assert_eq!(v4, Vector4::from_raw(glam::Vec4::new(1.0, 2.0, 3.0, 4.0))); } @@ -1198,6 +1197,12 @@ mod tests { assert_eq!(h1, h2); } + #[test] + fn odd_size() { + let v: Vector4 = Vector4::new(1, 2, 3, 4); + assert_eq!(size_of_val(&v), 4); + } + #[test] fn gaslight_coverage() { extern crate alloc; diff --git a/tests/compatibility.rs b/tests/compatibility.rs index 4a1702e..f1a60fe 100644 --- a/tests/compatibility.rs +++ b/tests/compatibility.rs @@ -1,4 +1,4 @@ -use glamour::{peel_mut, peel_ref, prelude::*}; +use glamour::{prelude::*}; #[test] fn into_iter() { @@ -10,61 +10,6 @@ fn into_iter() { assert_eq!(c, 10); } -#[test] -fn alignment() { - use core::mem::align_of; - - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert!(align_of::() <= align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert!(align_of::() <= align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert!(align_of::() <= align_of::>()); - - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert!(align_of::() <= align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert!(align_of::() <= align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert!(align_of::() <= align_of::>()); - - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert!(align_of::() <= align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert!(align_of::() <= align_of::>()); - - assert_eq!(align_of::(), align_of::>()); - assert_eq!(align_of::(), align_of::>()); - assert_eq!( - align_of::(), - align_of::>() - ); - assert!(align_of::() <= align_of::>()); -} - #[test] fn size() { use core::mem::size_of; @@ -117,270 +62,6 @@ fn size() { assert_eq!(size_of::(), size_of::>()); } -#[test] -fn cast_to_glam_by_reference() { - let mut vec2 = Vector2::::new(1.0, 2.0); - let mut vec3 = Vector3::::new(1.0, 2.0, 3.0); - let mut vec4 = Vector4::::new(1.0, 2.0, 3.0, 4.0); - let mut dvec2 = Vector2::::new(1.0, 2.0); - let mut dvec3 = Vector3::::new(1.0, 2.0, 3.0); - let mut dvec4 = Vector4::::new(1.0, 2.0, 3.0, 4.0); - let mut ivec2 = Vector2::::new(1, 2); - let mut ivec3 = Vector3::::new(1, 2, 3); - let mut ivec4 = Vector4::::new(1, 2, 3, 4); - let mut uvec2 = Vector2::::new(1u32, 2u32); - let mut uvec3 = Vector3::::new(1u32, 2u32, 3u32); - let mut uvec4 = Vector4::::new(1u32, 2u32, 3u32, 4u32); - - let mut point2 = Point2::::new(1.0, 2.0); - let mut point3 = Point3::::new(1.0, 2.0, 3.0); - let mut point4 = Point4::::new(1.0, 2.0, 3.0, 4.0); - let mut dpoint2 = Point2::::new(1.0, 2.0); - let mut dpoint3 = Point3::::new(1.0, 2.0, 3.0); - let mut dpoint4 = Point4::::new(1.0, 2.0, 3.0, 4.0); - let mut ipoint2 = Point2::::new(1, 2); - let mut ipoint3 = Point3::::new(1, 2, 3); - let mut ipoint4 = Point4::::new(1, 2, 3, 4); - let mut upoint2 = Point2::::new(1u32, 2u32); - let mut upoint3 = Point3::::new(1u32, 2u32, 3u32); - let mut upoint4 = Point4::::new(1u32, 2u32, 3u32, 4u32); - - let mut size2 = Size2::::new(1.0, 2.0); - let mut size3 = Size3::::new(1.0, 2.0, 3.0); - let mut dsize2 = Size2::::new(1.0, 2.0); - let mut dsize3 = Size3::::new(1.0, 2.0, 3.0); - let mut isize2 = Size2::::new(1, 2); - let mut isize3 = Size3::::new(1, 2, 3); - let mut usize2 = Size2::::new(1u32, 2u32); - let mut usize3 = Size3::::new(1u32, 2u32, 3u32); - - let mut mat2 = Matrix2::::IDENTITY; - let mut mat3 = Matrix3::::IDENTITY; - let mut mat4 = Matrix4::::IDENTITY; - let mut dmat2 = Matrix2::::IDENTITY; - let mut dmat3 = Matrix3::::IDENTITY; - let mut dmat4 = Matrix4::::IDENTITY; - - let vec2_raw: &glam::Vec2 = peel_ref(&vec2); - let vec3_raw: &glam::Vec3 = peel_ref(&vec3); - let vec4_raw: &glam::Vec4 = peel_ref(&vec4); - let dvec2_raw: &glam::DVec2 = peel_ref(&dvec2); - let dvec3_raw: &glam::DVec3 = peel_ref(&dvec3); - let dvec4_raw: &glam::DVec4 = peel_ref(&dvec4); - let ivec2_raw: &glam::IVec2 = peel_ref(&ivec2); - let ivec3_raw: &glam::IVec3 = peel_ref(&ivec3); - let ivec4_raw: &glam::IVec4 = peel_ref(&ivec4); - let uvec2_raw: &glam::UVec2 = peel_ref(&uvec2); - let uvec3_raw: &glam::UVec3 = peel_ref(&uvec3); - let uvec4_raw: &glam::UVec4 = peel_ref(&uvec4); - - let point2_raw: &glam::Vec2 = peel_ref(&point2); - let point3_raw: &glam::Vec3 = peel_ref(&point3); - let point4_raw: &glam::Vec4 = peel_ref(&point4); - let dpoint2_raw: &glam::DVec2 = peel_ref(&dpoint2); - let dpoint3_raw: &glam::DVec3 = peel_ref(&dpoint3); - let dpoint4_raw: &glam::DVec4 = peel_ref(&dpoint4); - let ipoint2_raw: &glam::IVec2 = peel_ref(&ipoint2); - let ipoint3_raw: &glam::IVec3 = peel_ref(&ipoint3); - let ipoint4_raw: &glam::IVec4 = peel_ref(&ipoint4); - let upoint2_raw: &glam::UVec2 = peel_ref(&upoint2); - let upoint3_raw: &glam::UVec3 = peel_ref(&upoint3); - let upoint4_raw: &glam::UVec4 = peel_ref(&upoint4); - - let size2_raw: &glam::Vec2 = peel_ref(&size2); - let size3_raw: &glam::Vec3 = peel_ref(&size3); - let dsize2_raw: &glam::DVec2 = peel_ref(&dsize2); - let dsize3_raw: &glam::DVec3 = peel_ref(&dsize3); - let isize2_raw: &glam::IVec2 = peel_ref(&isize2); - let isize3_raw: &glam::IVec3 = peel_ref(&isize3); - let usize2_raw: &glam::UVec2 = peel_ref(&usize2); - let usize3_raw: &glam::UVec3 = peel_ref(&usize3); - - let mat2_raw: &glam::Mat2 = peel_ref(&mat2); - let mat3_raw: &glam::Mat3 = peel_ref(&mat3); - let mat4_raw: &glam::Mat4 = peel_ref(&mat4); - let dmat2_raw: &glam::DMat2 = peel_ref(&dmat2); - let dmat3_raw: &glam::DMat3 = peel_ref(&dmat3); - let dmat4_raw: &glam::DMat4 = peel_ref(&dmat4); - - assert_eq!(vec2_raw.x, vec2.x); - assert_eq!(vec2_raw.y, vec2.y); - assert_eq!(vec3_raw.x, vec3.x); - assert_eq!(vec3_raw.y, vec3.y); - assert_eq!(vec3_raw.z, vec3.z); - assert_eq!(vec4_raw.x, vec4.x); - assert_eq!(vec4_raw.y, vec4.y); - assert_eq!(vec4_raw.z, vec4.z); - assert_eq!(vec4_raw.w, vec4.w); - assert_eq!(dvec2_raw.x, dvec2.x); - assert_eq!(dvec2_raw.y, dvec2.y); - assert_eq!(dvec3_raw.z, dvec3.z); - assert_eq!(dvec3_raw.x, dvec3.x); - assert_eq!(dvec3_raw.y, dvec3.y); - assert_eq!(dvec4_raw.x, dvec4.x); - assert_eq!(dvec4_raw.y, dvec4.y); - assert_eq!(dvec4_raw.z, dvec4.z); - assert_eq!(dvec4_raw.w, dvec4.w); - assert_eq!(ivec2_raw.x, ivec2.x); - assert_eq!(ivec2_raw.y, ivec2.y); - assert_eq!(ivec3_raw.x, ivec3.x); - assert_eq!(ivec3_raw.y, ivec3.y); - assert_eq!(ivec3_raw.z, ivec3.z); - assert_eq!(ivec4_raw.x, ivec4.x); - assert_eq!(ivec4_raw.y, ivec4.y); - assert_eq!(ivec4_raw.z, ivec4.z); - assert_eq!(ivec4_raw.w, ivec4.w); - assert_eq!(uvec2_raw.x, uvec2.x); - assert_eq!(uvec2_raw.y, uvec2.y); - assert_eq!(uvec3_raw.x, uvec3.x); - assert_eq!(uvec3_raw.y, uvec3.y); - assert_eq!(uvec3_raw.z, uvec3.z); - assert_eq!(uvec4_raw.x, uvec4.x); - assert_eq!(uvec4_raw.y, uvec4.y); - assert_eq!(uvec4_raw.z, uvec4.z); - assert_eq!(uvec4_raw.w, uvec4.w); - assert_eq!(point2_raw.x, point2.x); - assert_eq!(point2_raw.y, point2.y); - assert_eq!(point3_raw.x, point3.x); - assert_eq!(point3_raw.y, point3.y); - assert_eq!(point3_raw.z, point3.z); - assert_eq!(point4_raw.x, point4.x); - assert_eq!(point4_raw.y, point4.y); - assert_eq!(point4_raw.z, point4.z); - assert_eq!(point4_raw.w, point4.w); - assert_eq!(dpoint2_raw.x, dpoint2.x); - assert_eq!(dpoint2_raw.y, dpoint2.y); - assert_eq!(dpoint3_raw.z, dpoint3.z); - assert_eq!(dpoint3_raw.x, dpoint3.x); - assert_eq!(dpoint3_raw.y, dpoint3.y); - assert_eq!(dpoint4_raw.x, dpoint4.x); - assert_eq!(dpoint4_raw.y, dpoint4.y); - assert_eq!(dpoint4_raw.z, dpoint4.z); - assert_eq!(dpoint4_raw.w, dpoint4.w); - assert_eq!(ipoint2_raw.x, ipoint2.x); - assert_eq!(ipoint2_raw.y, ipoint2.y); - assert_eq!(ipoint3_raw.x, ipoint3.x); - assert_eq!(ipoint3_raw.y, ipoint3.y); - assert_eq!(ipoint3_raw.z, ipoint3.z); - assert_eq!(ipoint4_raw.x, ipoint4.x); - assert_eq!(ipoint4_raw.y, ipoint4.y); - assert_eq!(ipoint4_raw.z, ipoint4.z); - assert_eq!(ipoint4_raw.w, ipoint4.w); - assert_eq!(upoint2_raw.x, upoint2.x); - assert_eq!(upoint2_raw.y, upoint2.y); - assert_eq!(upoint3_raw.x, upoint3.x); - assert_eq!(upoint3_raw.y, upoint3.y); - assert_eq!(upoint3_raw.z, upoint3.z); - assert_eq!(upoint4_raw.x, upoint4.x); - assert_eq!(upoint4_raw.y, upoint4.y); - assert_eq!(upoint4_raw.z, upoint4.z); - assert_eq!(upoint4_raw.w, upoint4.w); - - assert_eq!(size2_raw.x, size2.width); - assert_eq!(size2_raw.y, size2.height); - assert_eq!(size3_raw.x, size3.width); - assert_eq!(size3_raw.y, size3.height); - assert_eq!(size3_raw.z, size3.depth); - assert_eq!(dsize2_raw.x, dsize2.width); - assert_eq!(dsize2_raw.y, dsize2.height); - assert_eq!(dsize3_raw.z, dsize3.depth); - assert_eq!(dsize3_raw.x, dsize3.width); - assert_eq!(dsize3_raw.y, dsize3.height); - assert_eq!(isize2_raw.x, isize2.width); - assert_eq!(isize2_raw.y, isize2.height); - assert_eq!(isize3_raw.x, isize3.width); - assert_eq!(isize3_raw.y, isize3.height); - assert_eq!(isize3_raw.z, isize3.depth); - assert_eq!(usize2_raw.x, usize2.width); - assert_eq!(usize2_raw.y, usize2.height); - assert_eq!(usize3_raw.x, usize3.width); - assert_eq!(usize3_raw.y, usize3.height); - assert_eq!(usize3_raw.z, usize3.depth); - - assert_eq!(*mat2_raw, glam::Mat2::IDENTITY); - assert_eq!(*mat3_raw, glam::Mat3::IDENTITY); - assert_eq!(*mat4_raw, glam::Mat4::IDENTITY); - assert_eq!(*dmat2_raw, glam::DMat2::IDENTITY); - assert_eq!(*dmat3_raw, glam::DMat3::IDENTITY); - assert_eq!(*dmat4_raw, glam::DMat4::IDENTITY); - - let _vec2_raw: &glam::Vec2 = peel_ref(&vec2); - let _vec3_raw: &glam::Vec3 = peel_ref(&vec3); - let _vec4_raw: &glam::Vec4 = peel_ref(&vec4); - let _dvec2_raw: &glam::DVec2 = peel_ref(&dvec2); - let _dvec3_raw: &glam::DVec3 = peel_ref(&dvec3); - let _dvec4_raw: &glam::DVec4 = peel_ref(&dvec4); - let _ivec2_raw: &glam::IVec2 = peel_ref(&ivec2); - let _ivec3_raw: &glam::IVec3 = peel_ref(&ivec3); - let _ivec4_raw: &glam::IVec4 = peel_ref(&ivec4); - let _uvec2_raw: &glam::UVec2 = peel_ref(&uvec2); - let _uvec3_raw: &glam::UVec3 = peel_ref(&uvec3); - let _uvec4_raw: &glam::UVec4 = peel_ref(&uvec4); - - let _point2_raw: &glam::Vec2 = peel_ref(&point2); - let _point3_raw: &glam::Vec3 = peel_ref(&point3); - let _point4_raw: &glam::Vec4 = peel_ref(&point4); - let _dpoint2_raw: &glam::DVec2 = peel_ref(&dpoint2); - let _dpoint3_raw: &glam::DVec3 = peel_ref(&dpoint3); - let _dpoint4_raw: &glam::DVec4 = peel_ref(&dpoint4); - let _ipoint2_raw: &glam::IVec2 = peel_ref(&ipoint2); - let _ipoint3_raw: &glam::IVec3 = peel_ref(&ipoint3); - let _ipoint4_raw: &glam::IVec4 = peel_ref(&ipoint4); - let _upoint2_raw: &glam::UVec2 = peel_ref(&upoint2); - let _upoint3_raw: &glam::UVec3 = peel_ref(&upoint3); - let _upoint4_raw: &glam::UVec4 = peel_ref(&upoint4); - - let _size2_raw: &glam::Vec2 = peel_ref(&size2); - let _size3_raw: &glam::Vec3 = peel_ref(&size3); - let _dsize2_raw: &glam::DVec2 = peel_ref(&dsize2); - let _dsize3_raw: &glam::DVec3 = peel_ref(&dsize3); - let _isize2_raw: &glam::IVec2 = peel_ref(&isize2); - let _isize3_raw: &glam::IVec3 = peel_ref(&isize3); - let _usize2_raw: &glam::UVec2 = peel_ref(&usize2); - let _usize3_raw: &glam::UVec3 = peel_ref(&usize3); - - let _vec2_raw: &mut glam::Vec2 = peel_mut(&mut vec2); - let _vec3_raw: &mut glam::Vec3 = peel_mut(&mut vec3); - let _vec4_raw: &mut glam::Vec4 = peel_mut(&mut vec4); - let _dvec2_raw: &mut glam::DVec2 = peel_mut(&mut dvec2); - let _dvec3_raw: &mut glam::DVec3 = peel_mut(&mut dvec3); - let _dvec4_raw: &mut glam::DVec4 = peel_mut(&mut dvec4); - let _ivec2_raw: &mut glam::IVec2 = peel_mut(&mut ivec2); - let _ivec3_raw: &mut glam::IVec3 = peel_mut(&mut ivec3); - let _ivec4_raw: &mut glam::IVec4 = peel_mut(&mut ivec4); - let _uvec2_raw: &mut glam::UVec2 = peel_mut(&mut uvec2); - let _uvec3_raw: &mut glam::UVec3 = peel_mut(&mut uvec3); - let _uvec4_raw: &mut glam::UVec4 = peel_mut(&mut uvec4); - - let _point2_raw: &mut glam::Vec2 = peel_mut(&mut point2); - let _point3_raw: &mut glam::Vec3 = peel_mut(&mut point3); - let _point4_raw: &mut glam::Vec4 = peel_mut(&mut point4); - let _dpoint2_raw: &mut glam::DVec2 = peel_mut(&mut dpoint2); - let _dpoint3_raw: &mut glam::DVec3 = peel_mut(&mut dpoint3); - let _dpoint4_raw: &mut glam::DVec4 = peel_mut(&mut dpoint4); - let _ipoint2_raw: &mut glam::IVec2 = peel_mut(&mut ipoint2); - let _ipoint3_raw: &mut glam::IVec3 = peel_mut(&mut ipoint3); - let _ipoint4_raw: &mut glam::IVec4 = peel_mut(&mut ipoint4); - let _upoint2_raw: &mut glam::UVec2 = peel_mut(&mut upoint2); - let _upoint3_raw: &mut glam::UVec3 = peel_mut(&mut upoint3); - let _upoint4_raw: &mut glam::UVec4 = peel_mut(&mut upoint4); - - let _size2_raw: &mut glam::Vec2 = peel_mut(&mut size2); - let _size3_raw: &mut glam::Vec3 = peel_mut(&mut size3); - let _dsize2_raw: &mut glam::DVec2 = peel_mut(&mut dsize2); - let _dsize3_raw: &mut glam::DVec3 = peel_mut(&mut dsize3); - let _isize2_raw: &mut glam::IVec2 = peel_mut(&mut isize2); - let _isize3_raw: &mut glam::IVec3 = peel_mut(&mut isize3); - let _usize2_raw: &mut glam::UVec2 = peel_mut(&mut usize2); - let _usize3_raw: &mut glam::UVec3 = peel_mut(&mut usize3); - - let _mat2_raw: &mut glam::Mat2 = peel_mut(&mut mat2); - let _mat3_raw: &mut glam::Mat3 = peel_mut(&mut mat3); - let _mat4_raw: &mut glam::Mat4 = peel_mut(&mut mat4); - let _dmat2_raw: &mut glam::DMat2 = peel_mut(&mut dmat2); - let _dmat3_raw: &mut glam::DMat3 = peel_mut(&mut dmat3); - let _dmat4_raw: &mut glam::DMat4 = peel_mut(&mut dmat4); -} #[test] fn from_into_glam() { diff --git a/tests/static_assertions.rs b/tests/static_assertions.rs index 557f046..52d51c0 100644 --- a/tests/static_assertions.rs +++ b/tests/static_assertions.rs @@ -227,37 +227,6 @@ impl AssertScalable for Vector4 {} impl AssertScalable for Size2 {} impl AssertScalable for Size3 {} -impl AssertRefConversion for Point2 {} -impl AssertRefConversion for Size2 {} -impl AssertRefConversion for Vector2 {} -impl AssertRefConversion for Point3 {} -impl AssertRefConversion for Size3 {} -impl AssertRefConversion for Vector3 {} -impl AssertRefConversion for Point4 {} -impl AssertRefConversion for Vector4 {} -impl AssertRefConversion for Point2 {} -impl AssertRefConversion for Vector2 {} -impl AssertRefConversion for Point3 {} -impl AssertRefConversion for Vector3 {} -impl AssertRefConversion for Point4 {} -impl AssertRefConversion for Vector4 {} -impl AssertRefConversion for Point2 {} -impl AssertRefConversion for Size2 {} -impl AssertRefConversion for Vector2 {} -impl AssertRefConversion for Point3 {} -impl AssertRefConversion for Size3 {} -impl AssertRefConversion for Vector3 {} -impl AssertRefConversion for Point4 {} -impl AssertRefConversion for Vector4 {} -impl AssertRefConversion for Point2 {} -impl AssertRefConversion for Size2 {} -impl AssertRefConversion for Vector2 {} -impl AssertRefConversion for Point3 {} -impl AssertRefConversion for Size3 {} -impl AssertRefConversion for Vector3 {} -impl AssertRefConversion for Point4 {} -impl AssertRefConversion for Vector4 {} - impl AssertRefConversion<[f64; 2]> for Point2 {} impl AssertRefConversion<[f64; 2]> for Size2 {} impl AssertRefConversion<[f64; 2]> for Vector2 {} From 57bed0cb05d9a5225d543766aa220173ceaecf61 Mon Sep 17 00:00:00 2001 From: Simon Ask Ulsnes Date: Thu, 8 May 2025 07:46:04 +0200 Subject: [PATCH 2/5] cargo fmt --- src/point.rs | 5 +---- src/vector.rs | 5 +---- tests/compatibility.rs | 3 +-- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/point.rs b/src/point.rs index 43d0ca9..f1df286 100644 --- a/src/point.rs +++ b/src/point.rs @@ -92,10 +92,7 @@ impl Transparent for Point3 { /// aligned (for some reason), and integer vectors are only 4-byte aligned, /// which means that reference-casting from those glam types to `Point4` type /// will fail (but not the other way around). -#[cfg_attr( - not(target_arch = "spirv"), - repr(C) -)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] #[cfg_attr( all(not(target_arch = "wasm32"), feature = "wasmtime"), derive( diff --git a/src/vector.rs b/src/vector.rs index 3006899..9f809ed 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -119,10 +119,7 @@ impl Transparent for Vector3 { /// This is always has the same alignment as the scalar component type, and /// _not_ the "normal" 128-bit alignment. This is due to limitations in the /// `#[repr(align(...))]` attribute when combined with generics. -#[cfg_attr( - not(target_arch = "spirv"), - repr(C) -)] +#[cfg_attr(not(target_arch = "spirv"), repr(C))] #[cfg_attr( all(not(target_arch = "wasm32"), feature = "wasmtime"), derive( diff --git a/tests/compatibility.rs b/tests/compatibility.rs index f1a60fe..7e4d9e5 100644 --- a/tests/compatibility.rs +++ b/tests/compatibility.rs @@ -1,4 +1,4 @@ -use glamour::{prelude::*}; +use glamour::prelude::*; #[test] fn into_iter() { @@ -62,7 +62,6 @@ fn size() { assert_eq!(size_of::(), size_of::>()); } - #[test] fn from_into_glam() { let f: Vector4 = vec4![1.0, 2.0, 3.0, 4.0]; From 5bff5ab328a6fa0666a088e0d2efa7382581d209 Mon Sep 17 00:00:00 2001 From: Simon Ask Ulsnes Date: Thu, 8 May 2025 08:33:02 +0200 Subject: [PATCH 3/5] Add codegen-check, verify --- CHANGELOG.md | 3 ++- Cargo.toml | 2 +- codegen-check/Cargo.toml | 11 +++++++++++ codegen-check/lib.rs | 25 +++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 codegen-check/Cargo.toml create mode 100644 codegen-check/lib.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 87a2bb9..e754e08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `glam::U8Vec4` has alignment 1. In general, it is brittle to rely on the specific alignment of `glam` vector types, because they are highly architecture dependent, and it is unlikely that it gains anything, because - unaligned vector register loads are no longer slow. + unaligned vector register loads are no longer slow (with AVX, the `vaddps` + instruction supports unaligned loads natively). ## [0.17.0] - 2025-05-03 diff --git a/Cargo.toml b/Cargo.toml index 99d5510..2b910d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["tests/wasmtime-guest"] +members = [ "codegen-check","tests/wasmtime-guest"] [package] name = "glamour" diff --git a/codegen-check/Cargo.toml b/codegen-check/Cargo.toml new file mode 100644 index 0000000..86ec4f2 --- /dev/null +++ b/codegen-check/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "codegen-check" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +path = "lib.rs" + +[dependencies] +glamour.path = ".." diff --git a/codegen-check/lib.rs b/codegen-check/lib.rs new file mode 100644 index 0000000..960a210 --- /dev/null +++ b/codegen-check/lib.rs @@ -0,0 +1,25 @@ +//! Codegen checks for the `glamour` crate. +//! +//! This is intended to be run manually when checking that glamour types +//! generate specific assembly output. +//! +//! 1. Install `cargo-show-asm` (`cargo install cargo-show-asm`). +//! 2. Run `cargo show-asm --release --target-cpu=native --target codegen-check +//! `, where `` is one of the functions below. +//! +//! Note that the `#[inline(never)]` is required to force the compiler to +//! generate the symbol. + +use glamour::Vector4; + +#[inline(never)] +pub fn sum_f32x4(v: &[Vector4]) -> Vector4 { + // This should generate a tight SIMD loop using unaligned loads or `vaddps` + // when the CPU supports it. + v.iter().copied().sum() +} + +#[inline(never)] +pub fn sum_u8x4(v: &[Vector4]) -> Vector4 { + v.iter().copied().sum() +} From 9acbd472219956621b3da3d37c7621e0c9180945 Mon Sep 17 00:00:00 2001 From: Simon Ask Ulsnes Date: Thu, 8 May 2025 08:40:43 +0200 Subject: [PATCH 4/5] Disable coverage for codegen-check --- codegen-check/Cargo.toml | 5 +++++ codegen-check/lib.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/codegen-check/Cargo.toml b/codegen-check/Cargo.toml index 86ec4f2..6cf3c73 100644 --- a/codegen-check/Cargo.toml +++ b/codegen-check/Cargo.toml @@ -9,3 +9,8 @@ path = "lib.rs" [dependencies] glamour.path = ".." + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(coverage,coverage_nightly)', +] } diff --git a/codegen-check/lib.rs b/codegen-check/lib.rs index 960a210..f5e2a9e 100644 --- a/codegen-check/lib.rs +++ b/codegen-check/lib.rs @@ -10,6 +10,8 @@ //! Note that the `#[inline(never)]` is required to force the compiler to //! generate the symbol. +#![cfg_attr(coverage, coverage(off))] + use glamour::Vector4; #[inline(never)] From a2601b9bc9570b7b03fb6c31f00827eb32fe1eb0 Mon Sep 17 00:00:00 2001 From: Simon Ask Ulsnes Date: Thu, 8 May 2025 08:45:20 +0200 Subject: [PATCH 5/5] Missing cfg(feature(coverage_attribute)) --- codegen-check/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/codegen-check/lib.rs b/codegen-check/lib.rs index f5e2a9e..a91e394 100644 --- a/codegen-check/lib.rs +++ b/codegen-check/lib.rs @@ -10,6 +10,7 @@ //! Note that the `#[inline(never)]` is required to force the compiler to //! generate the symbol. +#![cfg_attr(coverage, feature(coverage_attribute))] #![cfg_attr(coverage, coverage(off))] use glamour::Vector4;