From 5c8a08018268e4a3e2676bb64c528022d09d3d25 Mon Sep 17 00:00:00 2001 From: Philipp Dobler Date: Thu, 1 May 2025 15:17:21 +0200 Subject: [PATCH 1/4] Implement scalar operations for points. --- src/impl_ops.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/impl_ops.rs b/src/impl_ops.rs index e92e5e4..7555254 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -74,7 +74,35 @@ macro_rules! point_ops { crate::wrap(core::ops::Neg::neg(crate::peel(self))) } } + + // Need specific impls for each scalar types because the scalar is an associated type, + // so the compiler would think that the trait impls could overlap. + crate::impl_ops::point_ops!(@scalar $point_type_name, [f32, f64, i32, u32, i64, u64, i16, u16]); }; + + (@scalar $base_type_name:ident, [$($scalar:ident),*]) => { + $( + crate::impl_ops::impl_scalar_ops! { + Add<$scalar>::add for $base_type_name -> $base_type_name; + Sub<$scalar>::sub for $base_type_name -> $base_type_name; + Mul<$scalar>::mul for $base_type_name -> $base_type_name; + Div<$scalar>::div for $base_type_name -> $base_type_name; + Rem<$scalar>::rem for $base_type_name -> $base_type_name; + } + crate::impl_ops::impl_scalar_ops_rhs! { + Add<$scalar>::add for $base_type_name -> $base_type_name; + Sub<$scalar>::sub for $base_type_name -> $base_type_name; + Mul<$scalar>::mul for $base_type_name -> $base_type_name; + } + crate::impl_ops::impl_scalar_assign_ops! { + AddAssign<$scalar>::add_assign for $base_type_name; + SubAssign<$scalar>::sub_assign for $base_type_name; + MulAssign<$scalar>::mul_assign for $base_type_name; + DivAssign<$scalar>::div_assign for $base_type_name; + RemAssign<$scalar>::rem_assign for $base_type_name; + } + )* + } } pub(crate) use point_ops; From e8cc9965a6f8401f77584d33db3355e658f92422 Mon Sep 17 00:00:00 2001 From: Philipp Dobler Date: Thu, 1 May 2025 15:21:49 +0200 Subject: [PATCH 2/4] Implement missing point-point operation implementations. --- src/impl_ops.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/impl_ops.rs b/src/impl_ops.rs index 7555254..d63bcde 100644 --- a/src/impl_ops.rs +++ b/src/impl_ops.rs @@ -57,12 +57,14 @@ pub(crate) use vector_ops; macro_rules! point_ops { ($point_type_name:ident, $vector_type_name:ident) => { crate::impl_ops::impl_ops! { + Add<$point_type_name>::add for $point_type_name -> $point_type_name; Add<$vector_type_name>::add for $point_type_name -> $point_type_name; Sub<$point_type_name>::sub for $point_type_name -> $vector_type_name; Sub<$vector_type_name>::sub for $point_type_name -> $point_type_name; Rem<$point_type_name>::rem for $point_type_name -> $vector_type_name; } crate::impl_ops::impl_assign_ops! { + AddAssign<$point_type_name>::add_assign for $point_type_name; AddAssign<$vector_type_name>::add_assign for $point_type_name; SubAssign<$vector_type_name>::sub_assign for $point_type_name; RemAssign<$vector_type_name>::rem_assign for $point_type_name; @@ -74,12 +76,12 @@ macro_rules! point_ops { crate::wrap(core::ops::Neg::neg(crate::peel(self))) } } - + // Need specific impls for each scalar types because the scalar is an associated type, // so the compiler would think that the trait impls could overlap. crate::impl_ops::point_ops!(@scalar $point_type_name, [f32, f64, i32, u32, i64, u64, i16, u16]); }; - + (@scalar $base_type_name:ident, [$($scalar:ident),*]) => { $( crate::impl_ops::impl_scalar_ops! { From 51f7a7ee2b5383b22d264f9d7b980a18864888aa Mon Sep 17 00:00:00 2001 From: Philipp Dobler Date: Thu, 1 May 2025 15:33:49 +0200 Subject: [PATCH 3/4] Add test. --- src/point.rs | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/point.rs b/src/point.rs index ca95352..d561f5d 100644 --- a/src/point.rs +++ b/src/point.rs @@ -323,6 +323,45 @@ mod tests { type Point = super::Point3; + #[test] + #[expect(clippy::op_ref)] + fn ops_by_scalar_ref() { + let a = Point::new(1.0, 2.0, 3.0); + let b = 2.0; + let added = a + b; + let subtracted = a - b; + let multiplied = a * b; + + assert_eq!(a + &b, added); + assert_eq!(&a + b, added); + assert_eq!(&a + &b, added); + assert_eq!(b + &a, added); + assert_eq!(&b + a, added); + assert_eq!(&b + &a, added); + assert_eq!(a - &b, subtracted); + assert_eq!(&a - b, subtracted); + assert_eq!(&a - &b, subtracted); + assert_eq!(b - &a, subtracted); + assert_eq!(&b - a, subtracted); + assert_eq!(&b - &a, subtracted); + assert_eq!(a * &b, multiplied); + assert_eq!(&a * b, multiplied); + assert_eq!(&a * &b, multiplied); + assert_eq!(b * &a, multiplied); + assert_eq!(&b * a, multiplied); + assert_eq!(&b * &a, multiplied); + + let mut a2 = a; + a2 += &b; + assert_eq!(a2, added); + let mut a2 = a; + a2 -= &b; + assert_eq!(a2, subtracted); + let mut a2 = a; + a2 *= &b; + assert_eq!(a2, multiplied); + } + #[test] fn subtraction_yields_vector() { let p = Point::ONE; @@ -331,16 +370,6 @@ mod tests { assert_eq!(v, Vector3::::ZERO); } - #[test] - fn not_scalable() { - let p = Point::default(); - - // This should not compile: - // let q = p * 2.0; - - let _ = p; - } - #[test] fn vec3a() { let a: glam::Vec3A = Point::new(0.0, 1.0, 2.0).to_vec3a(); From 8a45fc84ba1380482b6e1007c92568b3487c1698 Mon Sep 17 00:00:00 2001 From: Simon Ask Ulsnes Date: Fri, 2 May 2025 14:40:36 +0200 Subject: [PATCH 4/4] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9793163..cc2bbb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for `u8` and `i8` scalars, mapping to `glam::U8Vec{N}` and `glam::I8Vec{N}`. - Implement right-hand side scalar `Add`, `Sub`, and `Mul` (#69). +- Implement scalar `Point` operations (#71). ### Breaking changes