diff --git a/CHANGELOG.md b/CHANGELOG.md index daac394..ab8f8da 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). - Implement `Mul` and `Mul` for `Matrix{3,4}`. ### Breaking changes diff --git a/src/impl_ops.rs b/src/impl_ops.rs index e92e5e4..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,7 +76,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; 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();