diff --git a/alloy/src/math.rs b/alloy/src/math.rs index de967fb..f1ca78d 100644 --- a/alloy/src/math.rs +++ b/alloy/src/math.rs @@ -3,3 +3,5 @@ mod angle; pub use angle::*; + +pub mod vec; diff --git a/alloy/src/math/vec.rs b/alloy/src/math/vec.rs new file mode 100644 index 0000000..9725aa8 --- /dev/null +++ b/alloy/src/math/vec.rs @@ -0,0 +1,124 @@ +//! Module containing vector definitions. +//! +//! Vectors can come in 2, 3, or 4-component forms, with a base of [`f32`], +//! [`i32`], or [`u32`], and in both owning and non-owning variations. +//! A non-owning variation allows for "views" of slices of primitive types, +//! and enable a common type that can be inherited with [`Deref`], or accessed +//! via [`Borrow`] or [`AsRef`]. +//! +//! Owning-variations are named with a full `VectorN`, whereas non-owned +//! types are defined as `VecN`, where `N` is the number of components. Below is +//! a complete table of all the defined types for this module: +//! +//! | Base Type | Owning | Non-Owning | +//! |-----------|--------------|------------| +//! | [`f32`] | [`Vector2`] | [`Vec2`] | +//! | [`i32`] | [`Vector2i`] | [`Vec2i`] | +//! | [`u32`] | [`Vector2u`] | [`Vec2u`] | +//! | [`f32`] | [`Vector3`] | [`Vec3`] | +//! | [`i32`] | [`Vector3i`] | [`Vec3i`] | +//! | [`u32`] | [`Vector3u`] | [`Vec3u`] | +//! | [`f32`] | [`Vector4`] | [`Vec4`] | +//! | [`i32`] | [`Vector4i`] | [`Vec4i`] | +//! | [`u32`] | [`Vector4u`] | [`Vec4u`] | +//! +//! [`Borrow`]: std::borrow::Borrow +//! [`Deref`]: std::ops::Deref +mod vec2; +mod vec2i; +mod vec2u; + +#[doc(inline)] +pub use vec2::*; +#[doc(inline)] +pub use vec2i::*; +#[doc(inline)] +pub use vec2u::*; + +mod vec3; +mod vec3i; +mod vec3u; + +#[doc(inline)] +pub use vec3::*; +#[doc(inline)] +pub use vec3i::*; +#[doc(inline)] +pub use vec3u::*; + +mod vec4; +mod vec4i; +mod vec4u; + +#[doc(inline)] +pub use vec4::*; +#[doc(inline)] +pub use vec4i::*; +#[doc(inline)] +pub use vec4u::*; + +impl From<&'_ Vec2i> for Vector2 { + #[inline] + fn from(value: &'_ Vec2i) -> Self { + Self { + x: value.x() as f32, + y: value.y() as f32, + } + } +} + +impl From<&'_ Vec2u> for Vector2 { + #[inline] + fn from(value: &'_ Vec2u) -> Self { + Self { + x: value.x() as f32, + y: value.y() as f32, + } + } +} + +impl From<&'_ Vec3i> for Vector3 { + #[inline] + fn from(value: &'_ Vec3i) -> Self { + Self { + x: value.x() as f32, + y: value.y() as f32, + z: value.z() as f32, + } + } +} + +impl From<&'_ Vec3u> for Vector3 { + #[inline] + fn from(value: &'_ Vec3u) -> Self { + Self { + x: value.x() as f32, + y: value.y() as f32, + z: value.z() as f32, + } + } +} + +impl From<&'_ Vec4i> for Vector4 { + #[inline] + fn from(value: &'_ Vec4i) -> Self { + Self { + x: value.x() as f32, + y: value.y() as f32, + z: value.z() as f32, + w: value.w() as f32, + } + } +} + +impl From<&'_ Vec4u> for Vector4 { + #[inline] + fn from(value: &'_ Vec4u) -> Self { + Self { + x: value.x() as f32, + y: value.y() as f32, + z: value.z() as f32, + w: value.w() as f32, + } + } +} diff --git a/alloy/src/math/vec/vec2.rs b/alloy/src/math/vec/vec2.rs new file mode 100644 index 0000000..ff4a9ca --- /dev/null +++ b/alloy/src/math/vec/vec2.rs @@ -0,0 +1,1072 @@ +use crate::cmp::{AlmostEq, Near}; +use crate::math::vec::{Vec2i, Vec2u}; +use crate::math::Angle; +use crate::ops::{Dot, Midpoint}; +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, + RemAssign, Sub, SubAssign, +}; +use std::slice::SliceIndex; + +/// A 2-component view of a vector-like object. +/// +/// [`Vec2`] objects are to [`Vector2`] as [`str`] is to [`String`]; that is to +/// say that [`Vec2`] objects represent an immutable view of the owning +/// [`Vector2`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd)] +pub struct Vec2([f32]); + +impl Vec2 { + /// Forms a reference to a [`Vec2`] from a slice of [`f32`]. + /// + /// This requires that `slice.len() == 2`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`f32`]s. + pub const fn from_slice(slice: &[f32]) -> Option<&Self> { + if slice.len() == 2 { + // SAFETY: Vec2 is transparent, and implemented directly in terms of a + // slice of f32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec2`] from a mutable slice of [`f32`]. + /// + /// This requires that `slice.len() == 2`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`f32`]s. + pub fn from_mut_slice(slice: &mut [f32]) -> Option<&mut Self> { + if slice.len() == 2 { + // SAFETY: Vec2 is transparent, and implemented directly in terms of a + // slice of f32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec2`] from a slice of [`f32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`f32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[f32]) -> &Self { + debug_assert!(slice.len() == 2); + // SAFETY: + // Vec2 is transparent, and implemented directly in terms of a + // slice of f32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + unsafe { std::mem::transmute(slice) } + } + + /// Forms a mutable reference to a [`Vec2`] from a slice of [`f32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`f32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [f32]) -> &mut Self { + debug_assert!(slice.len() == 2); + // SAFETY: See from_slice_unchecked + unsafe { std::mem::transmute(slice) } + } + + /// Forms a reference to a [`Vec2`] from a pointer to a contiguous sequence + /// of at least two [`f32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`f32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const f32) -> &'a Vec2 { + Vec2::from_slice_unchecked(std::slice::from_raw_parts(ptr, 2)) + } + + /// Forms a mutable reference to a [`Vec2`] from a pointer to a contiguous + /// sequence of at least two [`f32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`f32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut f32) -> &'a mut Vec2 { + Vec2::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 2)) + } + + /// Returns this [`Vec2`] as a slice of [`f32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[f32] { + &self.0 + } + + /// Returns this [`Vec2`] as a mutable slice of [`f32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [f32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 2-component vector. + #[inline(always)] + pub const fn x(&self) -> f32 { + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 2-component vector. + #[inline(always)] + pub const fn y(&self) -> f32 { + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns a mutable reference to the X-coordinate of this 2-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 2-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: f32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: f32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets all the components of this vector the values from other. + /// + /// # Arguments + /// + /// * `other` - the other [`Vec2`] to set. + pub fn set(&mut self, other: &Vec2) { + let src_ptr = other.as_ptr(); + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) = *src_ptr.add(i); + } + } + } + + /// Computes the square magnitude of this two-component vector. + #[inline(always)] + pub fn square_magnitude(&self) -> f32 { + self.dot(self) + } + + /// Computes the magnitude of this vector. + /// + /// Where possible, consider using [`Vec2::square_magnitude`] as this will + /// avoid the need to compute the square-root. + pub fn magnitude(&self) -> f32 { + self.square_magnitude().sqrt() + } + + /// Queries whether this vector is normalized (e.g. has a magnitude of 1). + pub fn is_normalized(&self) -> bool { + self.square_magnitude().almost_eq(&1.0) + } + + /// Normalizes this vector. + pub fn normalize(&mut self) { + *self /= self.magnitude() + } + + /// Rotates this vector around the origin by angle A. + /// + /// # Arguments + /// + /// * `angle` - the angle to rotate + pub fn rotate(&mut self, angle: A) { + let (cos, sin) = angle.sin_cos(); + let x = cos * self.x() - sin * self.y(); + let y = sin * self.x() + cos * self.y(); + + self.set_x(x); + self.set_y(y); + } +} + +impl Midpoint for Vec2 { + type Output = Vector2; + + fn midpoint(&self, other: &Self) -> Self::Output { + Vector2 { + x: (self.x() + other.x()) / 2.0, + y: (self.y() + other.y()) / 2.0, + } + } +} + +impl Near for Vec2 { + fn near(&self, other: &Self, tolerance: &f32) -> bool { + self.x().near(&other.x(), tolerance) && self.y().near(&other.y(), tolerance) + } +} + +impl AlmostEq for Vec2 { + fn almost_eq(&self, other: &Self) -> bool { + const EPSILON: f32 = 10.0 * std::f32::EPSILON; + self.near(other, &EPSILON) + } +} + +impl Index for Vec2 +where + I: SliceIndex<[f32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec2 +where + I: SliceIndex<[f32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec2 { + type Target = [f32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec2 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[f32]> for Vec2 { + #[inline(always)] + fn as_ref(&self) -> &[f32] { + &self.0 + } +} + +impl AsMut<[f32]> for Vec2 { + #[inline(always)] + fn as_mut(&mut self) -> &mut [f32] { + &mut self.0 + } +} + +impl Dot for Vec2 { + type Output = f32; + fn dot(&self, rhs: &Self) -> Self::Output { + self.x() * rhs.x() + self.y() * rhs.y() + } +} + +impl Add for &'_ Vec2 { + type Output = Vector2; + + fn add(self, rhs: Self) -> Self::Output { + Vector2 { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + } + } +} + +impl AddAssign<&Vec2> for Vec2 { + fn add_assign(&mut self, rhs: &Vec2) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + *dest_ptr += *src_ptr; + *dest_ptr.add(1) += *src_ptr.add(1); + } + } +} + +impl Sub for &'_ Vec2 { + type Output = Vector2; + + fn sub(self, rhs: Self) -> Self::Output { + Vector2 { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + } + } +} + +impl SubAssign<&Vec2> for Vec2 { + fn sub_assign(&mut self, rhs: &Vec2) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + *dest_ptr -= *src_ptr; + *dest_ptr.add(1) -= *src_ptr.add(1); + } + } +} + +impl Mul for &'_ Vec2 { + type Output = Vector2; + + fn mul(self, rhs: f32) -> Self::Output { + Vector2 { + x: self.x() * rhs, + y: self.y() * rhs, + } + } +} + +impl Mul<&'_ Vec2> for f32 { + type Output = Vector2; + + fn mul(self, rhs: &'_ Vec2) -> Self::Output { + Vector2 { + x: self * rhs.x(), + y: self * rhs.y(), + } + } +} + +impl MulAssign for Vec2 { + fn mul_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + *dest_ptr *= rhs; + *dest_ptr.add(1) *= rhs; + } + } +} + +impl Div for &'_ Vec2 { + type Output = Vector2; + + fn div(self, rhs: f32) -> Self::Output { + let inverse = 1.0 / rhs; + Vector2 { + x: self.x() * inverse, + y: self.y() * inverse, + } + } +} + +impl DivAssign for Vec2 { + fn div_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + let inverse = 1.0 / rhs; + unsafe { + *dest_ptr *= inverse; + *dest_ptr.add(1) *= inverse; + } + } +} + +impl Rem for &'_ Vec2 { + type Output = Vector2; + + fn rem(self, rhs: f32) -> Self::Output { + Vector2 { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + } + } +} + +impl RemAssign for Vec2 { + fn rem_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + *dest_ptr %= rhs; + *dest_ptr.add(1) %= rhs; + } + } +} + +impl Neg for &'_ Vec2 { + type Output = Vector2; + + fn neg(self) -> Self::Output { + Vector2 { + x: -self.x(), + y: -self.y(), + } + } +} + +impl std::fmt::Debug for Vec2 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec2") + .field("x", &self.x()) + .field("y", &self.y()) + .finish() + } +} + +impl std::fmt::Display for Vec2 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}}}", self.x(), self.y()) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec2`], which is solely referential, [`Vector2`] is an owning +/// instance. +#[repr(C)] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Debug)] +pub struct Vector2 { + /// The X-component of the vector. + pub x: f32, + /// The Y-component of the vector. + pub y: f32, +} + +impl Vector2 { + /// A constant for a unit vector in the positive X-direction. + pub const UNIT_X: Vector2 = Vector2::new(1.0, 0.0); + + /// A constant for a unit vector in the positive Y-direction. + pub const UNIT_Y: Vector2 = Vector2::new(0.0, 1.0); + + /// A constant for a unit vector in the negative X-direction. + pub const NEG_UNIT_X: Vector2 = Vector2::new(-1.0, 0.0); + + /// A constant for a unit vector in the negative Y-direction. + pub const NEG_UNIT_Y: Vector2 = Vector2::new(0.0, -1.0); + + /// Constructs this vector from an x and y coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + #[inline(always)] + pub const fn new(x: f32, y: f32) -> Self { + Self { x, y } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: f32) -> Self { + Self::new(v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[f32]) -> Option { + if slice.len() != 2 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[f32]) -> Self { + debug_assert!(slice.len() == 2); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 2 [`f32`] values. + pub const unsafe fn from_ptr(ptr: *const f32) -> Self { + Self::new(*ptr, *ptr.add(1)) + } + + /// Constructs this vector from a [`Vec2`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub const fn from_vec2(other: &Vec2) -> Self { + Self { + x: other.x(), + y: other.y(), + } + } + + /// Constructs this vector from a [`Vec2i`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub fn from_vec2i(other: &Vec2i) -> Self { + Self { + x: other.x() as f32, + y: other.y() as f32, + } + } + + /// Constructs this vector from a [`Vec2u`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub fn from_vec2u(other: &Vec2u) -> Self { + Self { + x: other.x() as f32, + y: other.y() as f32, + } + } + + /// Returns this vector as a [`Vec2`]. + #[inline(always)] + pub const fn as_vec2(&self) -> &Vec2 { + // SAFETY: + // + // Vector2 is repr(C) and thus points to two contiguous elements + // of type and align of `f32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `f32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const f32, + 2, + )) + } + } + + /// Returns this vector as a mutable [`Vec2`]. + #[inline(always)] + pub fn as_mut_vec2(&mut self) -> &mut Vec2 { + // SAFETY: See explanation in Borrow + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut f32, + 2, + )) + } + } + + /// Returns this vector as a slice of [`f32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[f32] { + self.as_vec2().as_slice() + } + + /// Returns this vector as a mutable slice of [`f32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [f32] { + self.as_mut_vec2().as_mut_slice() + } +} + +impl From<&'_ Vec2> for Vector2 { + #[inline(always)] + fn from(value: &'_ Vec2) -> Self { + value.to_owned() + } +} + +impl From for Vector2 +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl Add for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec2().add(rhs.as_vec2()) + } +} + +impl Add for Vector2 { + type Output = Vector2; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec2()) + } +} + +impl Add<&Vec2> for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn add(self, rhs: &Vec2) -> Self::Output { + self.as_vec2().add(rhs) + } +} + +impl Add<&Vector2> for &'_ Vec2 { + type Output = Vector2; + + #[inline(always)] + fn add(self, rhs: &Vector2) -> Self::Output { + self.add(rhs.as_vec2()) + } +} + +impl Add for &Vec2 { + type Output = Vector2; + + #[inline(always)] + fn add(self, rhs: Vector2) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec2> for Vector2 { + type Output = Vector2; + + fn add(mut self, rhs: &Vec2) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector2> for Vector2 { + type Output = Vector2; + + #[inline(always)] + fn add(self, rhs: &Vector2) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec2()) + } +} + +impl Add for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn add(self, rhs: Vector2) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec2().add(self) + } +} + +impl AddAssign for Vector2 { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec2().add_assign(&rhs) + } +} + +impl AddAssign<&Vector2> for Vector2 { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec2().add_assign(rhs) + } +} + +impl AddAssign<&Vec2> for Vector2 { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec2) { + self.as_mut_vec2().add_assign(rhs) + } +} + +impl Sub for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec2().sub(rhs.as_vec2()) + } +} + +impl Sub for Vector2 { + type Output = Vector2; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec2()) + } +} + +impl Sub<&Vec2> for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn sub(self, rhs: &Vec2) -> Self::Output { + self.as_vec2().sub(rhs) + } +} + +impl Sub<&Vector2> for &'_ Vec2 { + type Output = Vector2; + + #[inline(always)] + fn sub(self, rhs: &Vector2) -> Self::Output { + self.sub(rhs.as_vec2()) + } +} + +impl Sub for &Vec2 { + type Output = Vector2; + + #[inline(always)] + fn sub(self, rhs: Vector2) -> Self::Output { + self.sub(rhs.as_vec2()) + } +} + +impl Sub<&Vec2> for Vector2 { + type Output = Vector2; + + fn sub(mut self, rhs: &Vec2) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector2> for Vector2 { + type Output = Vector2; + + #[inline(always)] + fn sub(self, rhs: &Vector2) -> Self::Output { + self.sub(rhs.as_vec2()) + } +} + +impl Sub for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn sub(self, rhs: Vector2) -> Self::Output { + self.sub(rhs.as_vec2()) + } +} + +impl SubAssign for Vector2 { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec2().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector2> for Vector2 { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec2().sub_assign(rhs) + } +} + +impl SubAssign<&Vec2> for Vector2 { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec2) { + self.as_mut_vec2().sub_assign(rhs) + } +} + +impl Mul for Vector2 { + type Output = Vector2; + + #[inline(always)] + fn mul(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec2().mul_assign(rhs); + self + } +} + +impl Mul for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn mul(self, rhs: f32) -> Self::Output { + self.as_vec2().mul(rhs) + } +} + +impl Mul for f32 { + type Output = Vector2; + + #[inline(always)] + fn mul(self, mut rhs: Vector2) -> Self::Output { + rhs.as_mut_vec2().mul_assign(self); + rhs + } +} + +impl Mul<&Vector2> for f32 { + type Output = Vector2; + + #[inline(always)] + fn mul(self, rhs: &Vector2) -> Self::Output { + rhs.as_vec2().mul(self) + } +} + +impl MulAssign for Vector2 { + #[inline(always)] + fn mul_assign(&mut self, rhs: f32) { + self.as_mut_vec2().mul_assign(rhs) + } +} + +impl Div for Vector2 { + type Output = Vector2; + + #[inline(always)] + fn div(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec2().div_assign(rhs); + self + } +} + +impl Div for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn div(self, rhs: f32) -> Self::Output { + self.as_vec2().div(rhs) + } +} + +impl DivAssign for Vector2 { + #[inline(always)] + fn div_assign(&mut self, rhs: f32) { + self.as_mut_vec2().div_assign(rhs) + } +} + +impl Rem for Vector2 { + type Output = Vector2; + + #[inline(always)] + fn rem(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec2().rem_assign(rhs); + self + } +} + +impl Rem for &Vector2 { + type Output = Vector2; + + #[inline(always)] + fn rem(self, rhs: f32) -> Self::Output { + self.as_vec2().rem(rhs) + } +} + +impl RemAssign for Vector2 { + #[inline(always)] + fn rem_assign(&mut self, rhs: f32) { + self.as_mut_vec2().rem_assign(rhs) + } +} + +impl Deref for Vector2 { + type Target = Vec2; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector2 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector2 { + #[inline(always)] + fn borrow(&self) -> &Vec2 { + self.as_vec2() + } +} + +impl BorrowMut for Vector2 { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec2 { + self.as_mut_vec2() + } +} + +impl Borrow<[f32]> for Vector2 { + #[inline(always)] + fn borrow(&self) -> &[f32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[f32]> for Vector2 { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [f32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec2 { + type Owned = Vector2; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector2 { + x: self.x(), + y: self.y(), + } + } +} + +impl std::fmt::Display for Vector2 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}}}", self.x, self.y) + } +} + +#[cfg(test)] +mod test { + use crate::cmp::AlmostEq; + + use super::*; + + #[test] + fn test_vec2() { + let vec = Vector2::new(4.0, 2.0); + + use crate::cmp::AlmostEq; + let magnitude = vec.square_magnitude(); + + assert!(magnitude.almost_eq(&20.0)) + } + + #[test] + fn test_identity() { + let vec = Vector2::new(4.0, 2.0); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector2::new(4.0, 2.0); + + for v in vec.iter_mut() { + *v = *v * 2.0 + } + + assert!(vec.x.almost_eq(&8.0), "x = {}", vec.x); + assert!(vec.y.almost_eq(&4.0), "y = {}", vec.y); + } + + #[test] + fn test_add() { + let a = Vector2 { x: 10.0, y: 10.0 }; + let b = Vector2 { x: 0.0, y: 10.0 }; + + let c = a + b; + + assert!(c.almost_eq(&Vector2 { x: 10.0, y: 20.0 })) + } +} diff --git a/alloy/src/math/vec/vec2i.rs b/alloy/src/math/vec/vec2i.rs new file mode 100644 index 0000000..682584d --- /dev/null +++ b/alloy/src/math/vec/vec2i.rs @@ -0,0 +1,945 @@ +use crate::ops::Dot; +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, + RemAssign, Sub, SubAssign, +}; +use std::slice::SliceIndex; + +/// A 2-component view of a vector-like object. +/// +/// [`Vec2i`] objects are to [`Vector2i`] as [`str`] is to [`String`]; that is to +/// say that [`Vec2`] objects represent an immutable view of the owning +/// [`Vector2i`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd, Eq, Ord)] +pub struct Vec2i([i32]); + +impl Vec2i { + /// Forms a reference to a [`Vec2`] from a slice of [`i32`]. + /// + /// This requires that `slice.len() == 2`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`i32`]s. + pub const fn from_slice(slice: &[i32]) -> Option<&Self> { + if slice.len() == 2 { + // SAFETY: Vec2 is transparent, and implemented directly in terms of a + // slice of i32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec2`] from a mutable slice of [`i32`]. + /// + /// This requires that `slice.len() == 2`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`i32`]s. + pub fn from_mut_slice(slice: &mut [i32]) -> Option<&mut Self> { + if slice.len() == 2 { + // SAFETY: Vec2 is transparent, and implemented directly in terms of a + // slice of i32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec2`] from a slice of [`i32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`i32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[i32]) -> &Self { + debug_assert!(slice.len() == 2); + // SAFETY: + // Vec2 is transparent, and implemented directly in terms of a + // slice of i32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + unsafe { std::mem::transmute(slice) } + } + + /// Forms a mutable reference to a [`Vec2`] from a slice of [`i32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`i32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [i32]) -> &mut Self { + debug_assert!(slice.len() == 2); + // SAFETY: See from_slice_unchecked + unsafe { std::mem::transmute(slice) } + } + + /// Forms a reference to a [`Vec2`] from a pointer to a contiguous sequence + /// of at least two [`i32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`i32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const i32) -> &'a Vec2i { + Vec2i::from_slice_unchecked(std::slice::from_raw_parts(ptr, 2)) + } + + /// Forms a mutable reference to a [`Vec2`] from a pointer to a contiguous + /// sequence of at least two [`i32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`i32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut i32) -> &'a mut Vec2i { + Vec2i::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 2)) + } + + /// Returns this [`Vec2`] as a slice of [`i32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[i32] { + &self.0 + } + + /// Returns this [`Vec2`] as a mutable slice of [`i32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [i32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 2-component vector. + #[inline(always)] + pub const fn x(&self) -> i32 { + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 2-component vector. + #[inline(always)] + pub const fn y(&self) -> i32 { + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns a mutable reference to the X-coordinate of this 2-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 2-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: i32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: i32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets all the components of this vector the values from other. + /// + /// # Arguments + /// + /// * `other` - the other [`Vec2`] to set. + pub fn set(&mut self, other: &Vec2i) { + let src_ptr = other.as_ptr(); + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) = *src_ptr.add(i); + } + } + } +} + +impl Index for Vec2i +where + I: SliceIndex<[i32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec2i +where + I: SliceIndex<[i32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec2i { + type Target = [i32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec2i { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[i32]> for Vec2i { + #[inline(always)] + fn as_ref(&self) -> &[i32] { + &self.0 + } +} + +impl AsMut<[i32]> for Vec2i { + #[inline(always)] + fn as_mut(&mut self) -> &mut [i32] { + &mut self.0 + } +} + +impl Dot for Vec2i { + type Output = i32; + fn dot(&self, rhs: &Self) -> Self::Output { + self.x() * rhs.x() + self.y() * rhs.y() + } +} + +impl Add for &'_ Vec2i { + type Output = Vector2i; + + fn add(self, rhs: Self) -> Self::Output { + Vector2i { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + } + } +} + +impl AddAssign<&Vec2i> for Vec2i { + fn add_assign(&mut self, rhs: &Vec2i) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + *dest_ptr += *src_ptr; + *dest_ptr.add(1) += *src_ptr.add(1); + } + } +} + +impl Sub for &'_ Vec2i { + type Output = Vector2i; + + fn sub(self, rhs: Self) -> Self::Output { + Vector2i { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + } + } +} + +impl SubAssign<&Vec2i> for Vec2i { + fn sub_assign(&mut self, rhs: &Vec2i) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + *dest_ptr -= *src_ptr; + *dest_ptr.add(1) -= *src_ptr.add(1); + } + } +} + +impl Mul for &'_ Vec2i { + type Output = Vector2i; + + fn mul(self, rhs: i32) -> Self::Output { + Vector2i { + x: self.x() * rhs, + y: self.y() * rhs, + } + } +} + +impl Mul<&'_ Vec2i> for i32 { + type Output = Vector2i; + + fn mul(self, rhs: &'_ Vec2i) -> Self::Output { + Vector2i { + x: self * rhs.x(), + y: self * rhs.y(), + } + } +} + +impl MulAssign for Vec2i { + fn mul_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + *dest_ptr *= rhs; + *dest_ptr.add(1) *= rhs; + } + } +} + +impl Div for &'_ Vec2i { + type Output = Vector2i; + + fn div(self, rhs: i32) -> Self::Output { + Vector2i { + x: self.x() / rhs, + y: self.y() / rhs, + } + } +} + +impl DivAssign for Vec2i { + fn div_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + *dest_ptr /= rhs; + *dest_ptr.add(1) /= rhs; + } + } +} + +impl Rem for &'_ Vec2i { + type Output = Vector2i; + + fn rem(self, rhs: i32) -> Self::Output { + Vector2i { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + } + } +} + +impl RemAssign for Vec2i { + fn rem_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + *dest_ptr %= rhs; + *dest_ptr.add(1) %= rhs; + } + } +} + +impl Neg for &'_ Vec2i { + type Output = Vector2i; + + fn neg(self) -> Self::Output { + Vector2i { + x: -self.x(), + y: -self.y(), + } + } +} + +impl std::fmt::Debug for Vec2i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec2i") + .field("x", &self.x()) + .field("y", &self.y()) + .finish() + } +} + +impl std::fmt::Display for Vec2i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}}}", self.x(), self.y()) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec2`], which is solely referential, [`Vector2`] is an owning +/// instance. +#[repr(C)] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Debug, Eq, Ord)] +pub struct Vector2i { + /// The X-component of the vector. + pub x: i32, + /// The Y-component of the vector. + pub y: i32, +} + +impl Vector2i { + /// Constructs this vector from an x and y coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + #[inline(always)] + pub const fn new(x: i32, y: i32) -> Self { + Self { x, y } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: i32) -> Self { + Self::new(v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[i32]) -> Option { + if slice.len() != 2 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[i32]) -> Self { + debug_assert!(slice.len() == 2); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 2 [`i32`] values. + pub const unsafe fn from_ptr(ptr: *const i32) -> Self { + Self::new(*ptr, *ptr.add(1)) + } + + /// Returns this vector as a [`Vec2`]. + #[inline(always)] + pub const fn as_vec2i(&self) -> &Vec2i { + // SAFETY: + // + // Vector2 is repr(C) and thus points to two contiguous elements + // of type and align of `i32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `i32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const i32, + 2, + )) + } + } + + /// Returns this vector as a mutable [`Vec2`]. + #[inline(always)] + pub fn as_mut_vec2i(&mut self) -> &mut Vec2i { + // SAFETY: See explanation in Self::as_vec2i + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut i32, + 2, + )) + } + } + + /// Returns this vector as a slice of [`i32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[i32] { + self.as_vec2i().as_slice() + } + + /// Returns this vector as a mutable slice of [`i32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [i32] { + self.as_mut_vec2i().as_mut_slice() + } +} + +impl From<&'_ Vec2i> for Vector2i { + #[inline(always)] + fn from(value: &'_ Vec2i) -> Self { + value.to_owned() + } +} + +impl From for Vector2i +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl Add for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec2i().add(rhs.as_vec2i()) + } +} + +impl Add for Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec2i()) + } +} + +impl Add<&Vec2i> for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn add(self, rhs: &Vec2i) -> Self::Output { + self.as_vec2i().add(rhs) + } +} + +impl Add<&Vector2i> for &'_ Vec2i { + type Output = Vector2i; + + #[inline(always)] + fn add(self, rhs: &Vector2i) -> Self::Output { + self.add(rhs.as_vec2i()) + } +} + +impl Add for &Vec2i { + type Output = Vector2i; + + #[inline(always)] + fn add(self, rhs: Vector2i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec2i> for Vector2i { + type Output = Vector2i; + + fn add(mut self, rhs: &Vec2i) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector2i> for Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn add(self, rhs: &Vector2i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec2i()) + } +} + +impl Add for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn add(self, rhs: Vector2i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec2i().add(self) + } +} + +impl AddAssign for Vector2i { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec2i().add_assign(&rhs) + } +} + +impl AddAssign<&Vector2i> for Vector2i { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec2i().add_assign(rhs) + } +} + +impl AddAssign<&Vec2i> for Vector2i { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec2i) { + self.as_mut_vec2i().add_assign(rhs) + } +} + +impl Sub for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec2i().sub(rhs.as_vec2i()) + } +} + +impl Sub for Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec2i()) + } +} + +impl Sub<&Vec2i> for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn sub(self, rhs: &Vec2i) -> Self::Output { + self.as_vec2i().sub(rhs) + } +} + +impl Sub<&Vector2i> for &'_ Vec2i { + type Output = Vector2i; + + #[inline(always)] + fn sub(self, rhs: &Vector2i) -> Self::Output { + self.sub(rhs.as_vec2i()) + } +} + +impl Sub for &Vec2i { + type Output = Vector2i; + + #[inline(always)] + fn sub(self, rhs: Vector2i) -> Self::Output { + self.sub(rhs.as_vec2i()) + } +} + +impl Sub<&Vec2i> for Vector2i { + type Output = Vector2i; + + fn sub(mut self, rhs: &Vec2i) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector2i> for Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn sub(self, rhs: &Vector2i) -> Self::Output { + self.sub(rhs.as_vec2i()) + } +} + +impl Sub for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn sub(self, rhs: Vector2i) -> Self::Output { + self.sub(rhs.as_vec2i()) + } +} + +impl SubAssign for Vector2i { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec2i().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector2i> for Vector2i { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec2i().sub_assign(rhs) + } +} + +impl SubAssign<&Vec2i> for Vector2i { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec2i) { + self.as_mut_vec2i().sub_assign(rhs) + } +} + +impl Mul for Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn mul(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec2i().mul_assign(rhs); + self + } +} + +impl Mul for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn mul(self, rhs: i32) -> Self::Output { + self.as_vec2i().mul(rhs) + } +} + +impl Mul for i32 { + type Output = Vector2i; + + #[inline(always)] + fn mul(self, mut rhs: Vector2i) -> Self::Output { + rhs.as_mut_vec2i().mul_assign(self); + rhs + } +} + +impl Mul<&Vector2i> for i32 { + type Output = Vector2i; + + #[inline(always)] + fn mul(self, rhs: &Vector2i) -> Self::Output { + rhs.as_vec2i().mul(self) + } +} + +impl MulAssign for Vector2i { + #[inline(always)] + fn mul_assign(&mut self, rhs: i32) { + self.as_mut_vec2i().mul_assign(rhs) + } +} + +impl Div for Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn div(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec2i().div_assign(rhs); + self + } +} + +impl Div for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn div(self, rhs: i32) -> Self::Output { + self.as_vec2i().div(rhs) + } +} + +impl DivAssign for Vector2i { + #[inline(always)] + fn div_assign(&mut self, rhs: i32) { + self.as_mut_vec2i().div_assign(rhs) + } +} + +impl Rem for Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn rem(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec2i().rem_assign(rhs); + self + } +} + +impl Rem for &Vector2i { + type Output = Vector2i; + + #[inline(always)] + fn rem(self, rhs: i32) -> Self::Output { + self.as_vec2i().rem(rhs) + } +} + +impl RemAssign for Vector2i { + #[inline(always)] + fn rem_assign(&mut self, rhs: i32) { + self.as_mut_vec2i().rem_assign(rhs) + } +} + +impl Deref for Vector2i { + type Target = Vec2i; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector2i { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector2i { + #[inline(always)] + fn borrow(&self) -> &Vec2i { + self.as_vec2i() + } +} + +impl BorrowMut for Vector2i { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec2i { + self.as_mut_vec2i() + } +} + +impl Borrow<[i32]> for Vector2i { + #[inline(always)] + fn borrow(&self) -> &[i32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[i32]> for Vector2i { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [i32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec2i { + type Owned = Vector2i; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector2i { + x: self.x(), + y: self.y(), + } + } +} + +impl std::fmt::Display for Vector2i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}}}", self.x, self.y) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_identity() { + let vec = Vector2i::new(4, 2); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector2i::new(4, 2); + + for v in vec.iter_mut() { + *v = *v * 2 + } + + assert_eq!(vec.x, 8); + assert_eq!(vec.y, 4); + } + + #[test] + fn test_add() { + let a = Vector2i { x: 10, y: 10 }; + let b = Vector2i { x: 0, y: 10 }; + + let c = a + b; + + assert_eq!(c, Vector2i { x: 10, y: 20 }) + } +} diff --git a/alloy/src/math/vec/vec2u.rs b/alloy/src/math/vec/vec2u.rs new file mode 100644 index 0000000..bf114a2 --- /dev/null +++ b/alloy/src/math/vec/vec2u.rs @@ -0,0 +1,934 @@ +use crate::ops::Dot; +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Rem, RemAssign, + Sub, SubAssign, +}; +use std::slice::SliceIndex; + +/// A 2-component view of a vector-like object. +/// +/// [`Vec2u`] objects are to [`Vector2u`] as [`str`] is to [`String`]; that is to +/// say that [`Vec2`] objects represent an immutable view of the owning +/// [`Vector2u`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd, Eq, Ord)] +pub struct Vec2u([u32]); + +impl Vec2u { + /// Forms a reference to a [`Vec2`] from a slice of [`u32`]. + /// + /// This requires that `slice.len() == 2`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`u32`]s. + pub const fn from_slice(slice: &[u32]) -> Option<&Self> { + if slice.len() == 2 { + // SAFETY: Vec2 is transparent, and implemented directly in terms of a + // slice of u32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec2`] from a mutable slice of [`u32`]. + /// + /// This requires that `slice.len() == 2`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`u32`]s. + pub fn from_mut_slice(slice: &mut [u32]) -> Option<&mut Self> { + if slice.len() == 2 { + // SAFETY: Vec2 is transparent, and implemented directly in terms of a + // slice of u32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec2`] from a slice of [`u32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`u32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[u32]) -> &Self { + debug_assert!(slice.len() == 2); + // SAFETY: + // Vec2 is transparent, and implemented directly in terms of a + // slice of u32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + unsafe { std::mem::transmute(slice) } + } + + /// Forms a mutable reference to a [`Vec2`] from a slice of [`u32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`u32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [u32]) -> &mut Self { + debug_assert!(slice.len() == 2); + // SAFETY: See from_slice_unchecked + unsafe { std::mem::transmute(slice) } + } + + /// Forms a reference to a [`Vec2`] from a pointer to a contiguous sequence + /// of at least two [`u32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`u32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const u32) -> &'a Vec2u { + Vec2u::from_slice_unchecked(std::slice::from_raw_parts(ptr, 2)) + } + + /// Forms a mutable reference to a [`Vec2`] from a pointer to a contiguous + /// sequence of at least two [`u32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`u32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut u32) -> &'a mut Vec2u { + Vec2u::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 2)) + } + + /// Returns this [`Vec2`] as a slice of [`u32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[u32] { + &self.0 + } + + /// Returns this [`Vec2`] as a mutable slice of [`u32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [u32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 2-component vector. + #[inline(always)] + pub const fn x(&self) -> u32 { + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 2-component vector. + #[inline(always)] + pub const fn y(&self) -> u32 { + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns a mutable reference to the X-coordinate of this 2-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 2-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: u32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: u32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets all the components of this vector the values from other. + /// + /// # Arguments + /// + /// * `other` - the other [`Vec2`] to set. + pub fn set(&mut self, other: &Vec2u) { + let src_ptr = other.as_ptr(); + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) = *src_ptr.add(i); + } + } + } +} + +impl Index for Vec2u +where + I: SliceIndex<[u32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec2u +where + I: SliceIndex<[u32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec2u { + type Target = [u32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec2u { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[u32]> for Vec2u { + #[inline(always)] + fn as_ref(&self) -> &[u32] { + &self.0 + } +} + +impl AsMut<[u32]> for Vec2u { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u32] { + &mut self.0 + } +} + +impl Dot for Vec2u { + type Output = u32; + fn dot(&self, rhs: &Self) -> Self::Output { + self.x() * rhs.x() + self.y() * rhs.y() + } +} + +impl Add for &'_ Vec2u { + type Output = Vector2u; + + fn add(self, rhs: Self) -> Self::Output { + Vector2u { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + } + } +} + +impl AddAssign<&Vec2u> for Vec2u { + fn add_assign(&mut self, rhs: &Vec2u) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + *dest_ptr += *src_ptr; + *dest_ptr.add(1) += *src_ptr.add(1); + } + } +} + +impl Sub for &'_ Vec2u { + type Output = Vector2u; + + fn sub(self, rhs: Self) -> Self::Output { + Vector2u { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + } + } +} + +impl SubAssign<&Vec2u> for Vec2u { + fn sub_assign(&mut self, rhs: &Vec2u) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + *dest_ptr -= *src_ptr; + *dest_ptr.add(1) -= *src_ptr.add(1); + } + } +} + +impl Mul for &'_ Vec2u { + type Output = Vector2u; + + fn mul(self, rhs: u32) -> Self::Output { + Vector2u { + x: self.x() * rhs, + y: self.y() * rhs, + } + } +} + +impl Mul<&'_ Vec2u> for u32 { + type Output = Vector2u; + + fn mul(self, rhs: &'_ Vec2u) -> Self::Output { + Vector2u { + x: self * rhs.x(), + y: self * rhs.y(), + } + } +} + +impl MulAssign for Vec2u { + fn mul_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + *dest_ptr *= rhs; + *dest_ptr.add(1) *= rhs; + } + } +} + +impl Div for &'_ Vec2u { + type Output = Vector2u; + + fn div(self, rhs: u32) -> Self::Output { + Vector2u { + x: self.x() / rhs, + y: self.y() / rhs, + } + } +} + +impl DivAssign for Vec2u { + fn div_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + *dest_ptr /= rhs; + *dest_ptr.add(1) /= rhs; + } + } +} + +impl Rem for &'_ Vec2u { + type Output = Vector2u; + + fn rem(self, rhs: u32) -> Self::Output { + Vector2u { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + } + } +} + +impl RemAssign for Vec2u { + fn rem_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + *dest_ptr %= rhs; + *dest_ptr.add(1) %= rhs; + } + } +} + +impl std::fmt::Debug for Vec2u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec2u") + .field("x", &self.x()) + .field("y", &self.y()) + .finish() + } +} + +impl std::fmt::Display for Vec2u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}}}", self.x(), self.y()) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec2`], which is solely referential, [`Vector2`] is an owning +/// instance. +#[repr(C)] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Debug, Eq, Ord)] +pub struct Vector2u { + /// The X-component of the vector. + pub x: u32, + /// The Y-component of the vector. + pub y: u32, +} + +impl Vector2u { + /// Constructs this vector from an x and y coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + #[inline(always)] + pub const fn new(x: u32, y: u32) -> Self { + Self { x, y } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: u32) -> Self { + Self::new(v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[u32]) -> Option { + if slice.len() != 2 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[u32]) -> Self { + debug_assert!(slice.len() == 2); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 2 [`u32`] values. + pub const unsafe fn from_ptr(ptr: *const u32) -> Self { + Self::new(*ptr, *ptr.add(1)) + } + + /// Returns this vector as a [`Vec2`]. + #[inline(always)] + pub const fn as_vec2u(&self) -> &Vec2u { + // SAFETY: + // + // Vector2 is repr(C) and thus points to two contiguous elements + // of type and align of `u32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `u32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const u32, + 2, + )) + } + } + + /// Returns this vector as a mutable [`Vec2`]. + #[inline(always)] + pub fn as_mut_vec2u(&mut self) -> &mut Vec2u { + // SAFETY: See explanation in Self::as_vec2u + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut u32, + 2, + )) + } + } + + /// Returns this vector as a slice of [`u32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[u32] { + self.as_vec2u().as_slice() + } + + /// Returns this vector as a mutable slice of [`u32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [u32] { + self.as_mut_vec2u().as_mut_slice() + } +} + +impl From<&'_ Vec2u> for Vector2u { + #[inline(always)] + fn from(value: &'_ Vec2u) -> Self { + value.to_owned() + } +} + +impl From for Vector2u +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl Add for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec2u().add(rhs.as_vec2u()) + } +} + +impl Add for Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec2u()) + } +} + +impl Add<&Vec2u> for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn add(self, rhs: &Vec2u) -> Self::Output { + self.as_vec2u().add(rhs) + } +} + +impl Add<&Vector2u> for &'_ Vec2u { + type Output = Vector2u; + + #[inline(always)] + fn add(self, rhs: &Vector2u) -> Self::Output { + self.add(rhs.as_vec2u()) + } +} + +impl Add for &Vec2u { + type Output = Vector2u; + + #[inline(always)] + fn add(self, rhs: Vector2u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec2u> for Vector2u { + type Output = Vector2u; + + fn add(mut self, rhs: &Vec2u) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector2u> for Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn add(self, rhs: &Vector2u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec2u()) + } +} + +impl Add for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn add(self, rhs: Vector2u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec2u().add(self) + } +} + +impl AddAssign for Vector2u { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec2u().add_assign(&rhs) + } +} + +impl AddAssign<&Vector2u> for Vector2u { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec2u().add_assign(rhs) + } +} + +impl AddAssign<&Vec2u> for Vector2u { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec2u) { + self.as_mut_vec2u().add_assign(rhs) + } +} + +impl Sub for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec2u().sub(rhs.as_vec2u()) + } +} + +impl Sub for Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec2u()) + } +} + +impl Sub<&Vec2u> for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn sub(self, rhs: &Vec2u) -> Self::Output { + self.as_vec2u().sub(rhs) + } +} + +impl Sub<&Vector2u> for &'_ Vec2u { + type Output = Vector2u; + + #[inline(always)] + fn sub(self, rhs: &Vector2u) -> Self::Output { + self.sub(rhs.as_vec2u()) + } +} + +impl Sub for &Vec2u { + type Output = Vector2u; + + #[inline(always)] + fn sub(self, rhs: Vector2u) -> Self::Output { + self.sub(rhs.as_vec2u()) + } +} + +impl Sub<&Vec2u> for Vector2u { + type Output = Vector2u; + + fn sub(mut self, rhs: &Vec2u) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..2 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector2u> for Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn sub(self, rhs: &Vector2u) -> Self::Output { + self.sub(rhs.as_vec2u()) + } +} + +impl Sub for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn sub(self, rhs: Vector2u) -> Self::Output { + self.sub(rhs.as_vec2u()) + } +} + +impl SubAssign for Vector2u { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec2u().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector2u> for Vector2u { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec2u().sub_assign(rhs) + } +} + +impl SubAssign<&Vec2u> for Vector2u { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec2u) { + self.as_mut_vec2u().sub_assign(rhs) + } +} + +impl Mul for Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn mul(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec2u().mul_assign(rhs); + self + } +} + +impl Mul for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn mul(self, rhs: u32) -> Self::Output { + self.as_vec2u().mul(rhs) + } +} + +impl Mul for u32 { + type Output = Vector2u; + + #[inline(always)] + fn mul(self, mut rhs: Vector2u) -> Self::Output { + rhs.as_mut_vec2u().mul_assign(self); + rhs + } +} + +impl Mul<&Vector2u> for u32 { + type Output = Vector2u; + + #[inline(always)] + fn mul(self, rhs: &Vector2u) -> Self::Output { + rhs.as_vec2u().mul(self) + } +} + +impl MulAssign for Vector2u { + #[inline(always)] + fn mul_assign(&mut self, rhs: u32) { + self.as_mut_vec2u().mul_assign(rhs) + } +} + +impl Div for Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn div(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec2u().div_assign(rhs); + self + } +} + +impl Div for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn div(self, rhs: u32) -> Self::Output { + self.as_vec2u().div(rhs) + } +} + +impl DivAssign for Vector2u { + #[inline(always)] + fn div_assign(&mut self, rhs: u32) { + self.as_mut_vec2u().div_assign(rhs) + } +} + +impl Rem for Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn rem(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec2u().rem_assign(rhs); + self + } +} + +impl Rem for &Vector2u { + type Output = Vector2u; + + #[inline(always)] + fn rem(self, rhs: u32) -> Self::Output { + self.as_vec2u().rem(rhs) + } +} + +impl RemAssign for Vector2u { + #[inline(always)] + fn rem_assign(&mut self, rhs: u32) { + self.as_mut_vec2u().rem_assign(rhs) + } +} + +impl Deref for Vector2u { + type Target = Vec2u; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector2u { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector2u { + #[inline(always)] + fn borrow(&self) -> &Vec2u { + self.as_vec2u() + } +} + +impl BorrowMut for Vector2u { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec2u { + self.as_mut_vec2u() + } +} + +impl Borrow<[u32]> for Vector2u { + #[inline(always)] + fn borrow(&self) -> &[u32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[u32]> for Vector2u { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [u32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec2u { + type Owned = Vector2u; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector2u { + x: self.x(), + y: self.y(), + } + } +} + +impl std::fmt::Display for Vector2u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}}}", self.x, self.y) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_identity() { + let vec = Vector2u::new(4, 2); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector2u::new(4, 2); + + for v in vec.iter_mut() { + *v = *v * 2 + } + + assert_eq!(vec.x, 8); + assert_eq!(vec.y, 4); + } + + #[test] + fn test_add() { + let a = Vector2u { x: 10, y: 10 }; + let b = Vector2u { x: 0, y: 10 }; + + let c = a + b; + + assert_eq!(c, Vector2u { x: 10, y: 20 }) + } +} diff --git a/alloy/src/math/vec/vec3.rs b/alloy/src/math/vec/vec3.rs new file mode 100644 index 0000000..b79d22e --- /dev/null +++ b/alloy/src/math/vec/vec3.rs @@ -0,0 +1,1211 @@ +use crate::cmp::{AlmostEq, Near}; +use crate::math::vec::{Vec2, Vec3i, Vec3u}; +use crate::math::Angle; +use crate::ops::{Cross, Dot, Midpoint}; +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, + RemAssign, Sub, SubAssign, +}; + +/// A 3-component view of a vector-like object. +/// +/// [`Vec3`] objects are to [`Vector3`] as [`str`] is to [`String`]; that is to +/// say that [`Vec3`] objects represent an immutable view of the owning +/// [`Vector3`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd)] +pub struct Vec3([f32]); + +impl Vec3 { + /// Forms a reference to a [`Vec3`] from a slice of [`f32`]. + /// + /// This requires that `slice.len() == 3`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`f32`]s. + pub const fn from_slice(slice: &[f32]) -> Option<&Self> { + if slice.len() == 3 { + // SAFETY: Vec3 is transparent, and implemented directly in terms of a + // slice of f32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec3`] from a mutable slice of [`f32`]. + /// + /// This requires that `slice.len() == 3`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`f32`]s. + pub fn from_mut_slice(slice: &mut [f32]) -> Option<&mut Self> { + if slice.len() == 3 { + // SAFETY: Vec3 is transparent, and implemented directly in terms of a + // slice of f32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec3`] from a slice of [`f32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`f32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[f32]) -> &Self { + debug_assert!(slice.len() == 3); + // SAFETY: + // Vec3 is transparent, and implemented directly in terms of a + // slice of f32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + unsafe { std::mem::transmute(slice) } + } + + /// Forms a mutable reference to a [`Vec3`] from a slice of [`f32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`f32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [f32]) -> &mut Self { + debug_assert!(slice.len() == 3); + // SAFETY: See from_slice_unchecked + unsafe { std::mem::transmute(slice) } + } + + /// Forms a reference to a [`Vec3`] from a pointer to a contiguous sequence + /// of at least two [`f32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`f32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const f32) -> &'a Vec3 { + Vec3::from_slice_unchecked(std::slice::from_raw_parts(ptr, 3)) + } + + /// Forms a mutable reference to a [`Vec3`] from a pointer to a contiguous + /// sequence of at least two [`f32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`f32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut f32) -> &'a mut Vec3 { + Vec3::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 3)) + } + + /// Returns this [`Vec3`] as a slice of [`f32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[f32] { + &self.0 + } + + /// Returns this [`Vec3`] as a mutable slice of [`f32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [f32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 3-component vector. + #[inline(always)] + pub const fn x(&self) -> f32 { + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 3-component vector. + #[inline(always)] + pub const fn y(&self) -> f32 { + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns the Z-coordinate of this 3-component vector. + #[inline(always)] + pub const fn z(&self) -> f32 { + unsafe { *self.0.as_ptr().add(2) } + } + + /// Returns the xy coordinates of this vector as a [`Vec3`]. + #[inline(always)] + pub const fn xy(&self) -> &Vec2 { + unsafe { Vec2::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec3`]. + #[inline(always)] + pub const fn yz(&self) -> &Vec2 { + unsafe { Vec2::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns a mutable reference to the X-coordinate of this 3-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 3-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Returns a mutable reference to the Z-coordinate of this 3-component vector. + #[inline(always)] + pub fn z_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr().add(2) } + } + + /// Returns a mutable reference to the xy coordinates of this vector. + #[inline(always)] + pub fn xy_mut(&mut self) -> &mut Vec2 { + unsafe { Vec2::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn yz_mut(&mut self) -> &mut Vec2 { + unsafe { Vec2::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: f32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: f32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets the z-component + /// + /// # Arguments + /// + /// * `z` - the Z-component + #[inline(always)] + pub fn set_z(&mut self, z: f32) { + unsafe { *self.0.as_mut_ptr().add(2) = z } + } + + /// Sets the X and Y components of this vector + /// + /// # Arguments + /// + /// * `xy` - the X and Y components o + #[inline(always)] + pub fn set_xy(&mut self, xy: &Vec2) { + self.xy_mut().set(xy) + } + + /// Sets the Y and Z components of this vector + /// + /// # Arguments + /// + /// * `yz` - the Y and Z components of the [`Vec3`] + #[inline(always)] + pub fn set_yz(&mut self, xy: &Vec2) { + self.yz_mut().set(xy) + } + + /// Sets all the components of this vector the values from other. + /// + /// # Arguments + /// + /// * `other` - the other [`Vec3`] to set. + pub fn set(&mut self, other: &Vec3) { + let src_ptr = other.as_ptr(); + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) = *src_ptr.add(i); + } + } + } + + /// Computes the square magnitude of this two-component vector. + #[inline(always)] + pub fn square_magnitude(&self) -> f32 { + self.dot(self) + } + + /// Computes the magnitude of this vector. + /// + /// Where possible, consider using [`Vec3::square_magnitude`] as this will + /// avoid the need to compute the square-root. + pub fn magnitude(&self) -> f32 { + self.square_magnitude().sqrt() + } + + /// Queries whether this vector is normalized (e.g. has a magnitude of 1). + pub fn is_normalized(&self) -> bool { + self.square_magnitude().almost_eq(&1.0) + } + + /// Normalizes this vector. + pub fn normalize(&mut self) { + *self /= self.magnitude() + } + + /// Returns normalized vector. + pub fn normalized(&self) -> Vector3 { + self / self.magnitude() + } + + /// Rotates this vector around the X axis by angle A. + /// + /// # Arguments + /// + /// * `angle` - the angle to rotate + pub fn rotate_x(&mut self, angle: A) { + let (cos, sin) = angle.sin_cos(); + let y = cos * self.y() - sin * self.z(); + let z = sin * self.y() + cos * self.z(); + + self.set_y(y); + self.set_z(z); + } + + /// Rotates this vector around the Y axis by angle A. + /// + /// # Arguments + /// + /// * `angle` - the angle to rotate + pub fn rotate_y(&mut self, angle: A) { + let (cos, sin) = angle.sin_cos(); + let x = cos * self.x() + sin * self.z(); + let z = -sin * self.x() + cos * self.z(); + + self.set_x(x); + self.set_z(z); + } + + /// Rotates this vector around the Y axis by angle A. + /// + /// # Arguments + /// + /// * `angle` - the angle to rotate + pub fn rotate_z(&mut self, angle: A) { + let (cos, sin) = angle.sin_cos(); + let x = cos * self.x() - sin * self.y(); + let y = sin * self.x() + cos * self.y(); + + self.set_x(x); + self.set_y(y); + } +} + +impl Midpoint for Vec3 { + type Output = Vector3; + + fn midpoint(&self, other: &Self) -> Self::Output { + Vector3 { + x: (self.x() + other.x()) * 0.5, + y: (self.y() + other.y()) * 0.5, + z: (self.z() + other.z()) * 0.5, + } + } +} + +impl Near for Vec3 { + fn near(&self, other: &Self, tolerance: &f32) -> bool { + self.x().near(&other.x(), tolerance) + && self.y().near(&other.y(), tolerance) + && self.z().near(&other.z(), tolerance) + } +} + +impl AlmostEq for Vec3 { + fn almost_eq(&self, other: &Self) -> bool { + const EPSILON: f32 = 10.0 * std::f32::EPSILON; + self.near(other, &EPSILON) + } +} + +impl Index for Vec3 +where + I: std::slice::SliceIndex<[f32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec3 +where + I: std::slice::SliceIndex<[f32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec3 { + type Target = [f32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec3 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[f32]> for Vec3 { + #[inline(always)] + fn as_ref(&self) -> &[f32] { + &self.0 + } +} + +impl AsMut<[f32]> for Vec3 { + #[inline(always)] + fn as_mut(&mut self) -> &mut [f32] { + &mut self.0 + } +} + +impl Dot for Vec3 { + type Output = f32; + fn dot(&self, rhs: &Self) -> Self::Output { + self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z() + } +} + +impl Cross for Vec3 { + type Output = Vector3; + fn cross(&self, other: &Self) -> Self::Output { + Vector3 { + x: self.y() * other.z() - self.z() * other.y(), + y: self.z() * other.x() - self.x() * other.z(), + z: self.x() * other.y() - self.y() * other.x(), + } + } +} + +impl Add for &'_ Vec3 { + type Output = Vector3; + + fn add(self, rhs: Self) -> Self::Output { + Vector3 { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + z: self.z() + rhs.z(), + } + } +} + +impl AddAssign<&Vec3> for Vec3 { + fn add_assign(&mut self, rhs: &Vec3) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + } +} + +impl Sub for &'_ Vec3 { + type Output = Vector3; + + fn sub(self, rhs: Self) -> Self::Output { + Vector3 { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + z: self.z() - rhs.z(), + } + } +} + +impl SubAssign<&Vec3> for Vec3 { + fn sub_assign(&mut self, rhs: &Vec3) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + } +} + +impl Mul for &'_ Vec3 { + type Output = Vector3; + + fn mul(self, rhs: f32) -> Self::Output { + Vector3 { + x: self.x() * rhs, + y: self.y() * rhs, + z: self.z() * rhs, + } + } +} + +impl Mul<&'_ Vec3> for f32 { + type Output = Vector3; + + fn mul(self, rhs: &'_ Vec3) -> Self::Output { + Vector3 { + x: self * rhs.x(), + y: self * rhs.y(), + z: self * rhs.z(), + } + } +} + +impl MulAssign for Vec3 { + fn mul_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) *= rhs + } + } + } +} + +impl Div for &'_ Vec3 { + type Output = Vector3; + + fn div(self, rhs: f32) -> Self::Output { + let inverse = 1.0 / rhs; + Vector3 { + x: self.x() * inverse, + y: self.y() * inverse, + z: self.z() * inverse, + } + } +} + +impl DivAssign for Vec3 { + fn div_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + let inverse = 1.0 / rhs; + unsafe { + for i in 0..3 { + *dest_ptr.add(i) *= inverse + } + } + } +} + +impl Rem for &'_ Vec3 { + type Output = Vector3; + + fn rem(self, rhs: f32) -> Self::Output { + Vector3 { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + z: self.z().rem(rhs), + } + } +} + +impl RemAssign for Vec3 { + fn rem_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) %= rhs + } + } + } +} + +impl Neg for &'_ Vec3 { + type Output = Vector3; + + fn neg(self) -> Self::Output { + Vector3 { + x: -self.x(), + y: -self.y(), + z: -self.z(), + } + } +} + +impl std::fmt::Debug for Vec3 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec3") + .field("x", &self.x()) + .field("y", &self.y()) + .field("z", &self.z()) + .finish() + } +} + +impl std::fmt::Display for Vec3 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}}}", self.x(), self.y(), self.z()) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec3`], which is solely referential, [`Vector3`] is an owning +/// instance. +#[repr(C)] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Debug)] +pub struct Vector3 { + /// The X-component of the vector. + pub x: f32, + /// The Y-component of the vector. + pub y: f32, + /// The Z-component of the vector. + pub z: f32, +} + +impl Vector3 { + /// A constant for a unit vector in the positive X-direction. + pub const UNIT_X: Vector3 = Vector3::new(1.0, 0.0, 0.0); + + /// A constant for a unit vector in the positive Y-direction. + pub const UNIT_Y: Vector3 = Vector3::new(0.0, 1.0, 0.0); + + /// A constant for a unit vector in the positive Z-direction. + pub const UNIT_Z: Vector3 = Vector3::new(0.0, 0.0, 1.0); + + /// A constant for a unit vector in the negative X-direction. + pub const NEG_UNIT_X: Vector3 = Vector3::new(-1.0, 0.0, 0.0); + + /// A constant for a unit vector in the negative Y-direction. + pub const NEG_UNIT_Y: Vector3 = Vector3::new(0.0, -1.0, 0.0); + + /// A constant for a unit vector in the negative Z-direction. + pub const NEG_UNIT_Z: Vector3 = Vector3::new(0.0, 0.0, -1.0); + + /// Constructs this vector from an x, y, and z coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + /// * `z` - the z-component + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32) -> Self { + Self { x, y, z } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: f32) -> Self { + Self::new(v, v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[f32]) -> Option { + if slice.len() != 3 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + z: slice[3], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[f32]) -> Self { + debug_assert!(slice.len() == 3); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a [`Vec3`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub const fn from_vec3(other: &Vec3) -> Self { + Self { + x: other.x(), + y: other.y(), + z: other.z(), + } + } + + /// Constructs this vector from a [`Vec3i`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub fn from_vec3i(other: &Vec3i) -> Self { + Self { + x: other.x() as f32, + y: other.y() as f32, + z: other.z() as f32, + } + } + + /// Constructs this vector from a [`Vec3u`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub fn from_vec3u(other: &Vec3u) -> Self { + Self { + x: other.x() as f32, + y: other.y() as f32, + z: other.z() as f32, + } + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 3 [`f32`] values. + pub const unsafe fn from_ptr(ptr: *const f32) -> Self { + Self::new(*ptr, *ptr.add(1), *ptr.add(2)) + } + + /// Returns this vector as a [`Vec3`]. + #[inline(always)] + pub const fn as_vec3(&self) -> &Vec3 { + // SAFETY: + // + // Vector3 is repr(C) and thus points to two contiguous elements + // of type and align of `f32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `f32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const f32, + 3, + )) + } + } + + /// Returns this vector as a mutable [`Vec3`]. + #[inline(always)] + pub fn as_mut_vec3(&mut self) -> &mut Vec3 { + // SAFETY: See explanation in Borrow + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut f32, + 3, + )) + } + } + + /// Returns this vector as a slice of [`f32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[f32] { + self.as_vec3().as_slice() + } + + /// Returns this vector as a mutable slice of [`f32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [f32] { + self.as_mut_vec3().as_mut_slice() + } +} + +impl From for Vector3 +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl From<&'_ Vec3> for Vector3 { + #[inline(always)] + fn from(value: &'_ Vec3) -> Self { + value.to_owned() + } +} + +impl Add for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec3().add(rhs.as_vec3()) + } +} + +impl Add for Vector3 { + type Output = Vector3; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec3()) + } +} + +impl Add<&Vec3> for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn add(self, rhs: &Vec3) -> Self::Output { + self.as_vec3().add(rhs) + } +} + +impl Add<&Vector3> for &'_ Vec3 { + type Output = Vector3; + + #[inline(always)] + fn add(self, rhs: &Vector3) -> Self::Output { + self.add(rhs.as_vec3()) + } +} + +impl Add for &Vec3 { + type Output = Vector3; + + #[inline(always)] + fn add(self, rhs: Vector3) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec3> for Vector3 { + type Output = Vector3; + + fn add(mut self, rhs: &Vec3) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector3> for Vector3 { + type Output = Vector3; + + #[inline(always)] + fn add(self, rhs: &Vector3) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec3()) + } +} + +impl Add for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn add(self, rhs: Vector3) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec3().add(self) + } +} + +impl AddAssign for Vector3 { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec3().add_assign(&rhs) + } +} + +impl AddAssign<&Vector3> for Vector3 { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec3().add_assign(rhs) + } +} + +impl AddAssign<&Vec3> for Vector3 { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec3) { + self.as_mut_vec3().add_assign(rhs) + } +} + +impl Sub for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec3().sub(rhs.as_vec3()) + } +} + +impl Sub for Vector3 { + type Output = Vector3; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec3()) + } +} + +impl Sub<&Vec3> for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn sub(self, rhs: &Vec3) -> Self::Output { + self.as_vec3().sub(rhs) + } +} + +impl Sub<&Vector3> for &'_ Vec3 { + type Output = Vector3; + + #[inline(always)] + fn sub(self, rhs: &Vector3) -> Self::Output { + self.sub(rhs.as_vec3()) + } +} + +impl Sub for &Vec3 { + type Output = Vector3; + + #[inline(always)] + fn sub(self, rhs: Vector3) -> Self::Output { + self.sub(rhs.as_vec3()) + } +} + +impl Sub<&Vec3> for Vector3 { + type Output = Vector3; + + fn sub(mut self, rhs: &Vec3) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector3> for Vector3 { + type Output = Vector3; + + #[inline(always)] + fn sub(self, rhs: &Vector3) -> Self::Output { + self.sub(rhs.as_vec3()) + } +} + +impl Sub for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn sub(self, rhs: Vector3) -> Self::Output { + self.sub(rhs.as_vec3()) + } +} + +impl SubAssign for Vector3 { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec3().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector3> for Vector3 { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec3().sub_assign(rhs) + } +} + +impl SubAssign<&Vec3> for Vector3 { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec3) { + self.as_mut_vec3().sub_assign(rhs) + } +} + +impl Mul for Vector3 { + type Output = Vector3; + + #[inline(always)] + fn mul(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec3().mul_assign(rhs); + self + } +} + +impl Mul for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn mul(self, rhs: f32) -> Self::Output { + self.as_vec3().mul(rhs) + } +} + +impl Mul for f32 { + type Output = Vector3; + + #[inline(always)] + fn mul(self, mut rhs: Vector3) -> Self::Output { + rhs.as_mut_vec3().mul_assign(self); + rhs + } +} + +impl Mul<&Vector3> for f32 { + type Output = Vector3; + + #[inline(always)] + fn mul(self, rhs: &Vector3) -> Self::Output { + rhs.as_vec3().mul(self) + } +} + +impl MulAssign for Vector3 { + #[inline(always)] + fn mul_assign(&mut self, rhs: f32) { + self.as_mut_vec3().mul_assign(rhs) + } +} + +impl Div for Vector3 { + type Output = Vector3; + + #[inline(always)] + fn div(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec3().div_assign(rhs); + self + } +} + +impl Div for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn div(self, rhs: f32) -> Self::Output { + self.as_vec3().div(rhs) + } +} + +impl DivAssign for Vector3 { + #[inline(always)] + fn div_assign(&mut self, rhs: f32) { + self.as_mut_vec3().div_assign(rhs) + } +} + +impl Rem for Vector3 { + type Output = Vector3; + + #[inline(always)] + fn rem(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec3().rem_assign(rhs); + self + } +} + +impl Rem for &Vector3 { + type Output = Vector3; + + #[inline(always)] + fn rem(self, rhs: f32) -> Self::Output { + self.as_vec3().rem(rhs) + } +} + +impl RemAssign for Vector3 { + #[inline(always)] + fn rem_assign(&mut self, rhs: f32) { + self.as_mut_vec3().rem_assign(rhs) + } +} + +impl Deref for Vector3 { + type Target = Vec3; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector3 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector3 { + #[inline(always)] + fn borrow(&self) -> &Vec3 { + self.as_vec3() + } +} + +impl BorrowMut for Vector3 { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec3 { + self.as_mut_vec3() + } +} + +impl Borrow<[f32]> for Vector3 { + #[inline(always)] + fn borrow(&self) -> &[f32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[f32]> for Vector3 { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [f32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec3 { + type Owned = Vector3; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector3 { + x: self.x(), + y: self.y(), + z: self.z(), + } + } +} + +impl std::fmt::Display for Vector3 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}}}", self.x, self.y, self.z) + } +} + +#[cfg(test)] +mod test { + use crate::cmp::AlmostEq; + + use super::*; + + #[test] + fn test_vec3() { + let vec = Vector3::new(4.0, 2.0, 0.0); + + use crate::cmp::AlmostEq; + let magnitude = vec.square_magnitude(); + + assert!(magnitude.almost_eq(&20.0)) + } + + #[test] + fn test_identity() { + let vec = Vector3::new(4.0, 2.0, 0.0); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector3::new(4.0, 2.0, 1.0); + + for v in vec.iter_mut() { + *v = *v * 2.0 + } + + assert!(vec.x.almost_eq(&8.0), "x = {}", vec.x); + assert!(vec.y.almost_eq(&4.0), "y = {}", vec.y); + assert!(vec.z.almost_eq(&2.0), "z = {}", vec.z); + } + + #[test] + fn test_vec3_add() { + let mut lhs = Vector3::new(4.0, 2.0, 1.0); + lhs *= 4.0; + lhs += lhs.clone(); + lhs += Vector3::new(1.0, 1.0, 1.0); + assert!(lhs.dot(&Vector3::new(1.0, 1.0, 1.0)) != 0.0); + } +} diff --git a/alloy/src/math/vec/vec3i.rs b/alloy/src/math/vec/vec3i.rs new file mode 100644 index 0000000..19815da --- /dev/null +++ b/alloy/src/math/vec/vec3i.rs @@ -0,0 +1,1013 @@ +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, + RemAssign, Sub, SubAssign, +}; + +use super::Vec2i; + +/// A 3-component view of a vector-like object. +/// +/// [`Vec3i`] objects are to [`Vector3i`] as [`str`] is to [`String`]; that is to +/// say that [`Vec3i`] objects represent an immutable view of the owning +/// [`Vector3i`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd, Eq, Ord)] +pub struct Vec3i([i32]); + +impl Vec3i { + /// Forms a reference to a [`Vec3`] from a slice of [`i32`]. + /// + /// This requires that `slice.len() == 3`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`i32`]s. + pub const fn from_slice(slice: &[i32]) -> Option<&Self> { + if slice.len() == 3 { + // SAFETY: Vec3 is transparent, and implemented directly in terms of a + // slice of i32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec3`] from a mutable slice of [`i32`]. + /// + /// This requires that `slice.len() == 3`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`i32`]s. + pub fn from_mut_slice(slice: &mut [i32]) -> Option<&mut Self> { + if slice.len() == 3 { + // SAFETY: Vec3 is transparent, and implemented directly in terms of a + // slice of i32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec3`] from a slice of [`i32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`i32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[i32]) -> &Self { + debug_assert!(slice.len() == 3); + // SAFETY: + // Vec3 is transparent, and implemented directly in terms of a + // slice of i32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + unsafe { std::mem::transmute(slice) } + } + + /// Forms a mutable reference to a [`Vec3`] from a slice of [`i32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`i32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [i32]) -> &mut Self { + debug_assert!(slice.len() == 3); + // SAFETY: See from_slice_unchecked + unsafe { std::mem::transmute(slice) } + } + + /// Forms a reference to a [`Vec3`] from a pointer to a contiguous sequence + /// of at least two [`i32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`i32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const i32) -> &'a Vec3i { + Vec3i::from_slice_unchecked(std::slice::from_raw_parts(ptr, 3)) + } + + /// Forms a mutable reference to a [`Vec3`] from a pointer to a contiguous + /// sequence of at least two [`i32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`i32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut i32) -> &'a mut Vec3i { + Vec3i::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 3)) + } + + /// Returns this [`Vec3`] as a slice of [`i32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[i32] { + &self.0 + } + + /// Returns this [`Vec3`] as a mutable slice of [`i32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [i32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 3-component vector. + #[inline(always)] + pub const fn x(&self) -> i32 { + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 3-component vector. + #[inline(always)] + pub const fn y(&self) -> i32 { + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns the Z-coordinate of this 3-component vector. + #[inline(always)] + pub fn z(&self) -> i32 { + unsafe { *self.0.as_ptr().add(2) } + } + + /// Returns the xy coordinates of this vector as a [`Vec3`]. + #[inline(always)] + pub const fn xy(&self) -> &Vec2i { + unsafe { Vec2i::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec3`]. + #[inline(always)] + pub const fn yz(&self) -> &Vec2i { + unsafe { Vec2i::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns a mutable reference to the X-coordinate of this 3-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 3-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Returns a mutable reference to the Z-coordinate of this 3-component vector. + #[inline(always)] + pub fn z_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr().add(2) } + } + + /// Returns a mutable reference to the xy coordinates of this vector. + #[inline(always)] + pub fn xy_mut(&mut self) -> &mut Vec2i { + unsafe { Vec2i::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn yz_mut(&mut self) -> &mut Vec2i { + unsafe { Vec2i::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: i32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: i32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets the z-component + /// + /// # Arguments + /// + /// * `z` - the Z-component + #[inline(always)] + pub fn set_z(&mut self, z: i32) { + unsafe { *self.0.as_mut_ptr().add(2) = z } + } + + /// Sets the X and Y components of this vector + /// + /// # Arguments + /// + /// * `xy` - the X and Y components o + #[inline(always)] + pub fn set_xy(&mut self, xy: &Vec2i) { + self.xy_mut().set(xy) + } + + /// Sets the Y and Z components of this vector + /// + /// # Arguments + /// + /// * `yz` - the Y and Z components of the [`Vec3`] + #[inline(always)] + pub fn set_yz(&mut self, xy: &Vec2i) { + self.yz_mut().set(xy) + } + + /// Sets all the components of this vector the values from other. + /// + /// # Arguments + /// + /// * `other` - the other [`Vec3`] to set. + pub fn set(&mut self, other: &Vec3i) { + let src_ptr = other.as_ptr(); + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) = *src_ptr.add(i); + } + } + } +} + +impl Index for Vec3i +where + I: std::slice::SliceIndex<[i32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec3i +where + I: std::slice::SliceIndex<[i32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec3i { + type Target = [i32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec3i { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[i32]> for Vec3i { + #[inline(always)] + fn as_ref(&self) -> &[i32] { + &self.0 + } +} + +impl AsMut<[i32]> for Vec3i { + #[inline(always)] + fn as_mut(&mut self) -> &mut [i32] { + &mut self.0 + } +} + +impl Add for &'_ Vec3i { + type Output = Vector3i; + + fn add(self, rhs: Self) -> Self::Output { + Vector3i { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + z: self.z() + rhs.z(), + } + } +} + +impl AddAssign<&Vec3i> for Vec3i { + fn add_assign(&mut self, rhs: &Vec3i) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + } +} + +impl Sub for &'_ Vec3i { + type Output = Vector3i; + + fn sub(self, rhs: Self) -> Self::Output { + Vector3i { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + z: self.z() - rhs.z(), + } + } +} + +impl SubAssign<&Vec3i> for Vec3i { + fn sub_assign(&mut self, rhs: &Vec3i) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + } +} + +impl Mul for &'_ Vec3i { + type Output = Vector3i; + + fn mul(self, rhs: i32) -> Self::Output { + Vector3i { + x: self.x() * rhs, + y: self.y() * rhs, + z: self.z() * rhs, + } + } +} + +impl Mul<&'_ Vec3i> for i32 { + type Output = Vector3i; + + fn mul(self, rhs: &'_ Vec3i) -> Self::Output { + Vector3i { + x: self * rhs.x(), + y: self * rhs.y(), + z: self * rhs.z(), + } + } +} + +impl MulAssign for Vec3i { + fn mul_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) *= rhs + } + } + } +} + +impl Div for &'_ Vec3i { + type Output = Vector3i; + + fn div(self, rhs: i32) -> Self::Output { + Vector3i { + x: self.x() / rhs, + y: self.y() / rhs, + z: self.z() / rhs, + } + } +} + +impl DivAssign for Vec3i { + fn div_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) /= rhs + } + } + } +} + +impl Rem for &'_ Vec3i { + type Output = Vector3i; + + fn rem(self, rhs: i32) -> Self::Output { + Vector3i { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + z: self.z().rem(rhs), + } + } +} + +impl RemAssign for Vec3i { + fn rem_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) %= rhs + } + } + } +} + +impl Neg for &'_ Vec3i { + type Output = Vector3i; + + fn neg(self) -> Self::Output { + Vector3i { + x: -self.x(), + y: -self.y(), + z: -self.z(), + } + } +} + +impl std::fmt::Debug for Vec3i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec3i") + .field("x", &self.x()) + .field("y", &self.y()) + .field("z", &self.z()) + .finish() + } +} + +impl std::fmt::Display for Vec3i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}}}", self.x(), self.y(), self.z()) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec3`], which is solely referential, [`Vector3i`] is an owning +/// instance. +#[repr(C)] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Eq, Ord, Debug)] +pub struct Vector3i { + /// The X-component of the vector. + pub x: i32, + /// The Y-component of the vector. + pub y: i32, + /// The Z-component of the vector. + pub z: i32, +} + +impl Vector3i { + /// Constructs this vector from an x, y, and z coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + /// * `z` - the z-component + #[inline(always)] + pub const fn new(x: i32, y: i32, z: i32) -> Self { + Self { x, y, z } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: i32) -> Self { + Self::new(v, v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[i32]) -> Option { + if slice.len() != 3 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + z: slice[3], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[i32]) -> Self { + debug_assert!(slice.len() == 3); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 3 [`i32`] values. + pub const unsafe fn from_ptr(ptr: *const i32) -> Self { + Self::new(*ptr, *ptr.add(1), *ptr.add(2)) + } + + /// Returns this vector as a [`Vec3`]. + #[inline(always)] + pub const fn as_vec3i(&self) -> &Vec3i { + // SAFETY: + // + // Vector3i is repr(C) and thus points to two contiguous elements + // of type and align of `i32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `i32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const i32, + 3, + )) + } + } + + /// Returns this vector as a mutable [`Vec3`]. + #[inline(always)] + pub fn as_mut_vec3i(&mut self) -> &mut Vec3i { + // SAFETY: See explanation in Self::as_vec3 + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut i32, + 3, + )) + } + } + + /// Returns this vector as a slice of [`i32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[i32] { + self.as_vec3i().as_slice() + } + + /// Returns this vector as a mutable slice of [`i32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [i32] { + self.as_mut_vec3i().as_mut_slice() + } +} + +impl From for Vector3i +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl From<&'_ Vec3i> for Vector3i { + #[inline(always)] + fn from(value: &'_ Vec3i) -> Self { + value.to_owned() + } +} + +impl Add for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec3i().add(rhs.as_vec3i()) + } +} + +impl Add for Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec3i()) + } +} + +impl Add<&Vec3i> for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn add(self, rhs: &Vec3i) -> Self::Output { + self.as_vec3i().add(rhs) + } +} + +impl Add<&Vector3i> for &'_ Vec3i { + type Output = Vector3i; + + #[inline(always)] + fn add(self, rhs: &Vector3i) -> Self::Output { + self.add(rhs.as_vec3i()) + } +} + +impl Add for &Vec3i { + type Output = Vector3i; + + #[inline(always)] + fn add(self, rhs: Vector3i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec3i> for Vector3i { + type Output = Vector3i; + + fn add(mut self, rhs: &Vec3i) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector3i> for Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn add(self, rhs: &Vector3i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec3i()) + } +} + +impl Add for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn add(self, rhs: Vector3i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec3i().add(self) + } +} + +impl AddAssign for Vector3i { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec3i().add_assign(&rhs) + } +} + +impl AddAssign<&Vector3i> for Vector3i { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec3i().add_assign(rhs) + } +} + +impl AddAssign<&Vec3i> for Vector3i { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec3i) { + self.as_mut_vec3i().add_assign(rhs) + } +} + +impl Sub for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec3i().sub(rhs.as_vec3i()) + } +} + +impl Sub for Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec3i()) + } +} + +impl Sub<&Vec3i> for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn sub(self, rhs: &Vec3i) -> Self::Output { + self.as_vec3i().sub(rhs) + } +} + +impl Sub<&Vector3i> for &'_ Vec3i { + type Output = Vector3i; + + #[inline(always)] + fn sub(self, rhs: &Vector3i) -> Self::Output { + self.sub(rhs.as_vec3i()) + } +} + +impl Sub for &Vec3i { + type Output = Vector3i; + + #[inline(always)] + fn sub(self, rhs: Vector3i) -> Self::Output { + self.sub(rhs.as_vec3i()) + } +} + +impl Sub<&Vec3i> for Vector3i { + type Output = Vector3i; + + fn sub(mut self, rhs: &Vec3i) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector3i> for Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn sub(self, rhs: &Vector3i) -> Self::Output { + self.sub(rhs.as_vec3i()) + } +} + +impl Sub for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn sub(self, rhs: Vector3i) -> Self::Output { + self.sub(rhs.as_vec3i()) + } +} + +impl SubAssign for Vector3i { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec3i().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector3i> for Vector3i { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec3i().sub_assign(rhs) + } +} + +impl SubAssign<&Vec3i> for Vector3i { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec3i) { + self.as_mut_vec3i().sub_assign(rhs) + } +} + +impl Mul for Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn mul(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec3i().mul_assign(rhs); + self + } +} + +impl Mul for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn mul(self, rhs: i32) -> Self::Output { + self.as_vec3i().mul(rhs) + } +} + +impl Mul for i32 { + type Output = Vector3i; + + #[inline(always)] + fn mul(self, mut rhs: Vector3i) -> Self::Output { + rhs.as_mut_vec3i().mul_assign(self); + rhs + } +} + +impl Mul<&Vector3i> for i32 { + type Output = Vector3i; + + #[inline(always)] + fn mul(self, rhs: &Vector3i) -> Self::Output { + rhs.as_vec3i().mul(self) + } +} + +impl MulAssign for Vector3i { + #[inline(always)] + fn mul_assign(&mut self, rhs: i32) { + self.as_mut_vec3i().mul_assign(rhs) + } +} + +impl Div for Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn div(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec3i().div_assign(rhs); + self + } +} + +impl Div for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn div(self, rhs: i32) -> Self::Output { + self.as_vec3i().div(rhs) + } +} + +impl DivAssign for Vector3i { + #[inline(always)] + fn div_assign(&mut self, rhs: i32) { + self.as_mut_vec3i().div_assign(rhs) + } +} + +impl Rem for Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn rem(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec3i().rem_assign(rhs); + self + } +} + +impl Rem for &Vector3i { + type Output = Vector3i; + + #[inline(always)] + fn rem(self, rhs: i32) -> Self::Output { + self.as_vec3i().rem(rhs) + } +} + +impl RemAssign for Vector3i { + #[inline(always)] + fn rem_assign(&mut self, rhs: i32) { + self.as_mut_vec3i().rem_assign(rhs) + } +} + +impl Deref for Vector3i { + type Target = Vec3i; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector3i { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector3i { + #[inline(always)] + fn borrow(&self) -> &Vec3i { + self.as_vec3i() + } +} + +impl BorrowMut for Vector3i { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec3i { + self.as_mut_vec3i() + } +} + +impl Borrow<[i32]> for Vector3i { + #[inline(always)] + fn borrow(&self) -> &[i32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[i32]> for Vector3i { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [i32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec3i { + type Owned = Vector3i; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector3i { + x: self.x(), + y: self.y(), + z: self.z(), + } + } +} + +impl std::fmt::Display for Vector3i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}}}", self.x, self.y, self.z) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_identity() { + let vec = Vector3i::new(4, 2, 0); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector3i::new(4, 2, 1); + + for v in vec.iter_mut() { + *v = *v * 2 + } + + assert_eq!(vec.x, 8); + assert_eq!(vec.y, 4); + assert_eq!(vec.z, 2); + } +} diff --git a/alloy/src/math/vec/vec3u.rs b/alloy/src/math/vec/vec3u.rs new file mode 100644 index 0000000..a6ef1db --- /dev/null +++ b/alloy/src/math/vec/vec3u.rs @@ -0,0 +1,1001 @@ +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Rem, RemAssign, + Sub, SubAssign, +}; + +use super::Vec2u; + +/// A 3-component view of a vector-like object. +/// +/// [`Vec3u`] objects are to [`Vector3u`] as [`str`] is to [`String`]; that is to +/// say that [`Vec3u`] objects represent an immutable view of the owning +/// [`Vector3u`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd, Eq, Ord)] +pub struct Vec3u([u32]); + +impl Vec3u { + /// Forms a reference to a [`Vec3`] from a slice of [`u32`]. + /// + /// This requires that `slice.len() == 3`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`u32`]s. + pub const fn from_slice(slice: &[u32]) -> Option<&Self> { + if slice.len() == 3 { + // SAFETY: Vec3 is transparent, and implemented directly in terms of a + // slice of u32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec3`] from a mutable slice of [`u32`]. + /// + /// This requires that `slice.len() == 3`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`u32`]s. + pub fn from_mut_slice(slice: &mut [u32]) -> Option<&mut Self> { + if slice.len() == 3 { + // SAFETY: Vec3 is transparent, and implemented directly in terms of a + // slice of u32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec3`] from a slice of [`u32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`u32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[u32]) -> &Self { + debug_assert!(slice.len() == 3); + // SAFETY: + // Vec3 is transparent, and implemented directly in terms of a + // slice of u32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + unsafe { std::mem::transmute(slice) } + } + + /// Forms a mutable reference to a [`Vec3`] from a slice of [`u32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`u32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [u32]) -> &mut Self { + debug_assert!(slice.len() == 3); + // SAFETY: See from_slice_unchecked + unsafe { std::mem::transmute(slice) } + } + + /// Forms a reference to a [`Vec3`] from a pointer to a contiguous sequence + /// of at least two [`u32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`u32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const u32) -> &'a Vec3u { + Vec3u::from_slice_unchecked(std::slice::from_raw_parts(ptr, 3)) + } + + /// Forms a mutable reference to a [`Vec3`] from a pointer to a contiguous + /// sequence of at least two [`u32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`u32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut u32) -> &'a mut Vec3u { + Vec3u::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 3)) + } + + /// Returns this [`Vec3`] as a slice of [`u32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[u32] { + &self.0 + } + + /// Returns this [`Vec3`] as a mutable slice of [`u32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [u32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 3-component vector. + #[inline(always)] + pub const fn x(&self) -> u32 { + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 3-component vector. + #[inline(always)] + pub const fn y(&self) -> u32 { + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns the Z-coordinate of this 3-component vector. + #[inline(always)] + pub fn z(&self) -> u32 { + unsafe { *self.0.as_ptr().add(2) } + } + + /// Returns the xy coordinates of this vector as a [`Vec3`]. + #[inline(always)] + pub const fn xy(&self) -> &Vec2u { + unsafe { Vec2u::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec3`]. + #[inline(always)] + pub const fn yz(&self) -> &Vec2u { + unsafe { Vec2u::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns a mutable reference to the X-coordinate of this 3-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 3-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Returns a mutable reference to the Z-coordinate of this 3-component vector. + #[inline(always)] + pub fn z_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr().add(2) } + } + + /// Returns a mutable reference to the xy coordinates of this vector. + #[inline(always)] + pub fn xy_mut(&mut self) -> &mut Vec2u { + unsafe { Vec2u::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn yz_mut(&mut self) -> &mut Vec2u { + unsafe { Vec2u::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: u32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: u32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets the z-component + /// + /// # Arguments + /// + /// * `z` - the Z-component + #[inline(always)] + pub fn set_z(&mut self, z: u32) { + unsafe { *self.0.as_mut_ptr().add(2) = z } + } + + /// Sets the X and Y components of this vector + /// + /// # Arguments + /// + /// * `xy` - the X and Y components o + #[inline(always)] + pub fn set_xy(&mut self, xy: &Vec2u) { + self.xy_mut().set(xy) + } + + /// Sets the Y and Z components of this vector + /// + /// # Arguments + /// + /// * `yz` - the Y and Z components of the [`Vec3`] + #[inline(always)] + pub fn set_yz(&mut self, xy: &Vec2u) { + self.yz_mut().set(xy) + } + + /// Sets all the components of this vector the values from other. + /// + /// # Arguments + /// + /// * `other` - the other [`Vec3`] to set. + pub fn set(&mut self, other: &Vec3u) { + let src_ptr = other.as_ptr(); + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) = *src_ptr.add(i); + } + } + } +} + +impl Index for Vec3u +where + I: std::slice::SliceIndex<[u32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec3u +where + I: std::slice::SliceIndex<[u32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec3u { + type Target = [u32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec3u { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[u32]> for Vec3u { + #[inline(always)] + fn as_ref(&self) -> &[u32] { + &self.0 + } +} + +impl AsMut<[u32]> for Vec3u { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u32] { + &mut self.0 + } +} + +impl Add for &'_ Vec3u { + type Output = Vector3u; + + fn add(self, rhs: Self) -> Self::Output { + Vector3u { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + z: self.z() + rhs.z(), + } + } +} + +impl AddAssign<&Vec3u> for Vec3u { + fn add_assign(&mut self, rhs: &Vec3u) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + } +} + +impl Sub for &'_ Vec3u { + type Output = Vector3u; + + fn sub(self, rhs: Self) -> Self::Output { + Vector3u { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + z: self.z() - rhs.z(), + } + } +} + +impl SubAssign<&Vec3u> for Vec3u { + fn sub_assign(&mut self, rhs: &Vec3u) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + } +} + +impl Mul for &'_ Vec3u { + type Output = Vector3u; + + fn mul(self, rhs: u32) -> Self::Output { + Vector3u { + x: self.x() * rhs, + y: self.y() * rhs, + z: self.z() * rhs, + } + } +} + +impl Mul<&'_ Vec3u> for u32 { + type Output = Vector3u; + + fn mul(self, rhs: &'_ Vec3u) -> Self::Output { + Vector3u { + x: self * rhs.x(), + y: self * rhs.y(), + z: self * rhs.z(), + } + } +} + +impl MulAssign for Vec3u { + fn mul_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) *= rhs + } + } + } +} + +impl Div for &'_ Vec3u { + type Output = Vector3u; + + fn div(self, rhs: u32) -> Self::Output { + Vector3u { + x: self.x() / rhs, + y: self.y() / rhs, + z: self.z() / rhs, + } + } +} + +impl DivAssign for Vec3u { + fn div_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) /= rhs + } + } + } +} + +impl Rem for &'_ Vec3u { + type Output = Vector3u; + + fn rem(self, rhs: u32) -> Self::Output { + Vector3u { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + z: self.z().rem(rhs), + } + } +} + +impl RemAssign for Vec3u { + fn rem_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) %= rhs + } + } + } +} + +impl std::fmt::Debug for Vec3u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec3u") + .field("x", &self.x()) + .field("y", &self.y()) + .field("z", &self.z()) + .finish() + } +} + +impl std::fmt::Display for Vec3u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}}}", self.x(), self.y(), self.z()) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec3`], which is solely referential, [`Vector3u`] is an owning +/// instance. +#[repr(C)] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Eq, Ord, Debug)] +pub struct Vector3u { + /// The X-component of the vector. + pub x: u32, + /// The Y-component of the vector. + pub y: u32, + /// The Z-component of the vector. + pub z: u32, +} + +impl Vector3u { + /// Constructs this vector from an x, y, and z coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + /// * `z` - the z-component + #[inline(always)] + pub const fn new(x: u32, y: u32, z: u32) -> Self { + Self { x, y, z } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: u32) -> Self { + Self::new(v, v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[u32]) -> Option { + if slice.len() != 3 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + z: slice[3], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[u32]) -> Self { + debug_assert!(slice.len() == 3); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 3 [`u32`] values. + pub const unsafe fn from_ptr(ptr: *const u32) -> Self { + Self::new(*ptr, *ptr.add(1), *ptr.add(2)) + } + + /// Returns this vector as a [`Vec3`]. + #[inline(always)] + pub const fn as_vec3u(&self) -> &Vec3u { + // SAFETY: + // + // Vector3u is repr(C) and thus points to two contiguous elements + // of type and align of `u32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `u32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const u32, + 3, + )) + } + } + + /// Returns this vector as a mutable [`Vec3`]. + #[inline(always)] + pub fn as_mut_vec3u(&mut self) -> &mut Vec3u { + // SAFETY: See explanation in Self::as_vec3 + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut u32, + 3, + )) + } + } + + /// Returns this vector as a slice of [`u32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[u32] { + self.as_vec3u().as_slice() + } + + /// Returns this vector as a mutable slice of [`u32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [u32] { + self.as_mut_vec3u().as_mut_slice() + } +} + +impl From for Vector3u +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl From<&'_ Vec3u> for Vector3u { + #[inline(always)] + fn from(value: &'_ Vec3u) -> Self { + value.to_owned() + } +} + +impl Add for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec3u().add(rhs.as_vec3u()) + } +} + +impl Add for Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec3u()) + } +} + +impl Add<&Vec3u> for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn add(self, rhs: &Vec3u) -> Self::Output { + self.as_vec3u().add(rhs) + } +} + +impl Add<&Vector3u> for &'_ Vec3u { + type Output = Vector3u; + + #[inline(always)] + fn add(self, rhs: &Vector3u) -> Self::Output { + self.add(rhs.as_vec3u()) + } +} + +impl Add for &Vec3u { + type Output = Vector3u; + + #[inline(always)] + fn add(self, rhs: Vector3u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec3u> for Vector3u { + type Output = Vector3u; + + fn add(mut self, rhs: &Vec3u) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector3u> for Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn add(self, rhs: &Vector3u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec3u()) + } +} + +impl Add for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn add(self, rhs: Vector3u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec3u().add(self) + } +} + +impl AddAssign for Vector3u { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec3u().add_assign(&rhs) + } +} + +impl AddAssign<&Vector3u> for Vector3u { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec3u().add_assign(rhs) + } +} + +impl AddAssign<&Vec3u> for Vector3u { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec3u) { + self.as_mut_vec3u().add_assign(rhs) + } +} + +impl Sub for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec3u().sub(rhs.as_vec3u()) + } +} + +impl Sub for Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec3u()) + } +} + +impl Sub<&Vec3u> for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn sub(self, rhs: &Vec3u) -> Self::Output { + self.as_vec3u().sub(rhs) + } +} + +impl Sub<&Vector3u> for &'_ Vec3u { + type Output = Vector3u; + + #[inline(always)] + fn sub(self, rhs: &Vector3u) -> Self::Output { + self.sub(rhs.as_vec3u()) + } +} + +impl Sub for &Vec3u { + type Output = Vector3u; + + #[inline(always)] + fn sub(self, rhs: Vector3u) -> Self::Output { + self.sub(rhs.as_vec3u()) + } +} + +impl Sub<&Vec3u> for Vector3u { + type Output = Vector3u; + + fn sub(mut self, rhs: &Vec3u) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..3 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector3u> for Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn sub(self, rhs: &Vector3u) -> Self::Output { + self.sub(rhs.as_vec3u()) + } +} + +impl Sub for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn sub(self, rhs: Vector3u) -> Self::Output { + self.sub(rhs.as_vec3u()) + } +} + +impl SubAssign for Vector3u { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec3u().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector3u> for Vector3u { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec3u().sub_assign(rhs) + } +} + +impl SubAssign<&Vec3u> for Vector3u { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec3u) { + self.as_mut_vec3u().sub_assign(rhs) + } +} + +impl Mul for Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn mul(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec3u().mul_assign(rhs); + self + } +} + +impl Mul for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn mul(self, rhs: u32) -> Self::Output { + self.as_vec3u().mul(rhs) + } +} + +impl Mul for u32 { + type Output = Vector3u; + + #[inline(always)] + fn mul(self, mut rhs: Vector3u) -> Self::Output { + rhs.as_mut_vec3u().mul_assign(self); + rhs + } +} + +impl Mul<&Vector3u> for u32 { + type Output = Vector3u; + + #[inline(always)] + fn mul(self, rhs: &Vector3u) -> Self::Output { + rhs.as_vec3u().mul(self) + } +} + +impl MulAssign for Vector3u { + #[inline(always)] + fn mul_assign(&mut self, rhs: u32) { + self.as_mut_vec3u().mul_assign(rhs) + } +} + +impl Div for Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn div(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec3u().div_assign(rhs); + self + } +} + +impl Div for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn div(self, rhs: u32) -> Self::Output { + self.as_vec3u().div(rhs) + } +} + +impl DivAssign for Vector3u { + #[inline(always)] + fn div_assign(&mut self, rhs: u32) { + self.as_mut_vec3u().div_assign(rhs) + } +} + +impl Rem for Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn rem(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec3u().rem_assign(rhs); + self + } +} + +impl Rem for &Vector3u { + type Output = Vector3u; + + #[inline(always)] + fn rem(self, rhs: u32) -> Self::Output { + self.as_vec3u().rem(rhs) + } +} + +impl RemAssign for Vector3u { + #[inline(always)] + fn rem_assign(&mut self, rhs: u32) { + self.as_mut_vec3u().rem_assign(rhs) + } +} + +impl Deref for Vector3u { + type Target = Vec3u; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector3u { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector3u { + #[inline(always)] + fn borrow(&self) -> &Vec3u { + self.as_vec3u() + } +} + +impl BorrowMut for Vector3u { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec3u { + self.as_mut_vec3u() + } +} + +impl Borrow<[u32]> for Vector3u { + #[inline(always)] + fn borrow(&self) -> &[u32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[u32]> for Vector3u { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [u32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec3u { + type Owned = Vector3u; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector3u { + x: self.x(), + y: self.y(), + z: self.z(), + } + } +} + +impl std::fmt::Display for Vector3u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}}}", self.x, self.y, self.z) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_identity() { + let vec = Vector3u::new(4, 2, 0); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector3u::new(4, 2, 1); + + for v in vec.iter_mut() { + *v = *v * 2 + } + + assert_eq!(vec.x, 8); + assert_eq!(vec.y, 4); + assert_eq!(vec.z, 2); + } +} diff --git a/alloy/src/math/vec/vec4.rs b/alloy/src/math/vec/vec4.rs new file mode 100644 index 0000000..7c44a87 --- /dev/null +++ b/alloy/src/math/vec/vec4.rs @@ -0,0 +1,1265 @@ +use crate::cmp::{AlmostEq, Near}; +use crate::ops::{Cross, Dot, Midpoint}; +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, + RemAssign, Sub, SubAssign, +}; + +use super::{Vec2, Vec3, Vec4i, Vec4u}; + +/// A 4-component view of a vector-like object. +/// +/// [`Vec4`] objects are to [`Vector4`] as [`str`] is to [`String`]; that is to +/// say that [`Vec4`] objects represent an immutable view of the owning +/// [`Vector4`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd)] +pub struct Vec4([f32]); + +impl Vec4 { + /// Forms a reference to a [`Vec4`] from a slice of [`f32`]. + /// + /// This requires that `slice.len() == 4`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`f32`]s. + pub const fn from_slice(slice: &[f32]) -> Option<&Self> { + if slice.len() == 4 { + // SAFETY: Vec4 is transparent, and implemented directly in terms of a + // slice of f32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec4`] from a mutable slice of [`f32`]. + /// + /// This requires that `slice.len() == 4`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`f32`]s. + pub fn from_mut_slice(slice: &mut [f32]) -> Option<&mut Self> { + if slice.len() == 4 { + // SAFETY: Vec4 is transparent, and implemented directly in terms of a + // slice of f32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec4`] from a slice of [`f32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`f32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[f32]) -> &Self { + debug_assert!(slice.len() == 4); + std::mem::transmute(slice) + } + + /// Forms a mutable reference to a [`Vec4`] from a slice of [`f32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`f32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [f32]) -> &mut Self { + debug_assert!(slice.len() == 4); + std::mem::transmute(slice) + } + + /// Forms a reference to a [`Vec2`] from a pointer to a contiguous sequence + /// of at least two [`f32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`f32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const f32) -> &'a Vec4 { + Vec4::from_slice_unchecked(std::slice::from_raw_parts(ptr, 4)) + } + + /// Forms a mutable reference to a [`Vec3`] from a pointer to a contiguous + /// sequence of at least two [`f32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`f32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut f32) -> &'a mut Vec4 { + Vec4::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 4)) + } + + /// Returns this [`Vec4`] as a slice of [`f32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[f32] { + &self.0 + } + + /// Returns this [`Vec4`] as a mutable slice of [`f32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [f32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 4-component vector. + #[inline(always)] + pub const fn x(&self) -> f32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 4-component vector. + #[inline(always)] + pub const fn y(&self) -> f32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns the Z-coordinate of this 4-component vector. + #[inline(always)] + pub const fn z(&self) -> f32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(2) } + } + + /// Returns the W-coordinate of this 4-component vector. + #[inline(always)] + pub const fn w(&self) -> f32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(3) } + } + + /// Returns the xy coordinates of this vector as a [`Vec2`]. + #[inline(always)] + pub const fn xy(&self) -> &Vec2 { + unsafe { Vec2::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec2`]. + #[inline(always)] + pub const fn yz(&self) -> &Vec2 { + unsafe { Vec2::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns the zw coordinates of this vector as a [`Vec2`]. + #[inline(always)] + pub const fn zw(&self) -> &Vec2 { + unsafe { Vec2::from_ptr_unchecked(self.0.as_ptr().add(2)) } + } + + /// Returns the xyz coordinates of this vector as a [`Vec2`]. + #[inline(always)] + pub const fn xyz(&self) -> &Vec3 { + unsafe { Vec3::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec2`]. + #[inline(always)] + pub const fn yzw(&self) -> &Vec3 { + unsafe { Vec3::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns a mutable reference to the X-coordinate of this 3-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 3-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Returns a mutable reference to the Z-coordinate of this 3-component vector. + #[inline(always)] + pub fn z_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr().add(2) } + } + + /// Returns a mutable reference to the W-coordinate of this 3-component vector. + #[inline(always)] + pub fn w_mut(&mut self) -> &mut f32 { + unsafe { &mut *self.0.as_mut_ptr().add(3) } + } + + /// Returns a mutable reference to the xy coordinates of this vector. + #[inline(always)] + pub fn xy_mut(&mut self) -> &mut Vec2 { + unsafe { Vec2::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn yz_mut(&mut self) -> &mut Vec2 { + unsafe { Vec2::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Returns a mutable reference to the zw coordinates of this vector. + #[inline(always)] + pub fn zw_mut(&mut self) -> &mut Vec2 { + unsafe { Vec2::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(2)) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn xyz_mut(&mut self) -> &mut Vec3 { + unsafe { Vec3::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the zw coordinates of this vector. + #[inline(always)] + pub fn yzw_mut(&mut self) -> &mut Vec3 { + unsafe { Vec3::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: f32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: f32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets the z-component + /// + /// # Arguments + /// + /// * `z` - theZ-component + #[inline(always)] + pub fn set_z(&mut self, z: f32) { + unsafe { *self.0.as_mut_ptr().add(2) = z } + } + + /// Sets the w-component + /// + /// # Arguments + /// + /// * `w` - the W-component + #[inline(always)] + pub fn set_w(&mut self, w: f32) { + unsafe { *self.0.as_mut_ptr().add(3) = w } + } + + /// Sets the X and Y components of this vector + /// + /// # Arguments + /// + /// * `xy` - the X and Y components of the [`Vec4`] + #[inline(always)] + pub fn set_xy(&mut self, xy: &Vec2) { + self.xy_mut().set(xy) + } + + /// Sets the Y and Z components of this vector + /// + /// # Arguments + /// + /// * `yz` - the Y and Z components of the [`Vec4`] + #[inline(always)] + pub fn set_yz(&mut self, yz: &Vec2) { + self.yz_mut().set(yz) + } + + /// Sets the Z and W components of this vector + /// + /// # Arguments + /// + /// * `zw` - the Z and W components of the [`Vec4`] + #[inline(always)] + pub fn set_zw(&mut self, zw: &Vec2) { + self.zw_mut().set(zw) + } + + /// Sets the X, Y, and Z components of this vector + /// + /// # Arguments + /// + /// * `xyz` - the X, Y, and Z components of the [`Vec4`]` + #[inline(always)] + pub fn set_xyz(&mut self, xyz: &Vec3) { + self.xyz_mut().set(xyz) + } + + /// Sets the Y, Z and W components of this vector + /// + /// # Arguments + /// + /// * `yzw` - the Y, Z, and W components of the [`Vec4`] + #[inline(always)] + pub fn set_yzw(&mut self, yzw: &Vec3) { + self.yzw_mut().set(yzw) + } + + /// Computes the square magnitude of this two-component vector. + #[inline(always)] + pub fn square_magnitude(&self) -> f32 { + self.dot(self) + } + + /// Computes the magnitude of this vector. + /// + /// Where possible, consider using [`Vec4::square_magnitude`] as this will + /// avoid the need to compute the square-root. + pub fn magnitude(&self) -> f32 { + self.square_magnitude().sqrt() + } + + /// Queries whether this vector is normalized (e.g. has a magnitude of 1). + pub fn is_normalized(&self) -> bool { + self.square_magnitude().almost_eq(&1.0) + } + + /// Normalizes this vector. + pub fn normalize(&mut self) { + *self /= self.magnitude() + } + + /// Returns normalized vector. + pub fn normalized(&self) -> Vector4 { + self / self.magnitude() + } +} + +impl Midpoint for Vec4 { + type Output = Vector4; + + fn midpoint(&self, other: &Self) -> Self::Output { + Vector4 { + x: (self.x() + other.x()) * 0.5, + y: (self.y() + other.y()) * 0.5, + z: (self.z() + other.z()) * 0.5, + w: (self.w() + other.w()) * 0.5, + } + } +} + +impl Near for Vec4 { + fn near(&self, other: &Self, tolerance: &f32) -> bool { + self.x().near(&other.x(), tolerance) + && self.y().near(&other.y(), tolerance) + && self.z().near(&other.z(), tolerance) + && self.w().near(&other.w(), tolerance) + } +} + +impl AlmostEq for Vec4 { + fn almost_eq(&self, other: &Self) -> bool { + const EPSILON: f32 = 10.0 * std::f32::EPSILON; + self.near(other, &EPSILON) + } +} + +impl Index for Vec4 +where + I: std::slice::SliceIndex<[f32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec4 +where + I: std::slice::SliceIndex<[f32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec4 { + type Target = [f32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec4 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[f32]> for Vec4 { + #[inline(always)] + fn as_ref(&self) -> &[f32] { + &self.0 + } +} + +impl AsMut<[f32]> for Vec4 { + #[inline(always)] + fn as_mut(&mut self) -> &mut [f32] { + &mut self.0 + } +} + +impl Dot for Vec4 { + type Output = f32; + fn dot(&self, rhs: &Self) -> Self::Output { + self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z() + self.w() * rhs.w() + } +} + +impl Cross for Vec4 { + type Output = Vector4; + fn cross(&self, other: &Self) -> Self::Output { + Vector4 { + x: self.y() * other.z() - self.z() * other.y(), + y: self.z() * other.x() - self.x() * other.z(), + z: self.x() * other.y() - self.y() * other.x(), + w: 0.0, + } + } +} + +impl Add for &'_ Vec4 { + type Output = Vector4; + + fn add(self, rhs: Self) -> Self::Output { + Vector4 { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + z: self.z() + rhs.z(), + w: self.w() + rhs.w(), + } + } +} + +impl AddAssign<&Vec4> for Vec4 { + fn add_assign(&mut self, rhs: &Vec4) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + } +} + +impl Sub for &'_ Vec4 { + type Output = Vector4; + + fn sub(self, rhs: Self) -> Self::Output { + Vector4 { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + z: self.z() - rhs.z(), + w: self.w() - rhs.w(), + } + } +} + +impl SubAssign<&Vec4> for Vec4 { + fn sub_assign(&mut self, rhs: &Vec4) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + } +} + +impl Mul for &'_ Vec4 { + type Output = Vector4; + + fn mul(self, rhs: f32) -> Self::Output { + Vector4 { + x: self.x() * rhs, + y: self.y() * rhs, + z: self.z() * rhs, + w: self.w() * rhs, + } + } +} + +impl Mul<&'_ Vec4> for f32 { + type Output = Vector4; + + fn mul(self, rhs: &'_ Vec4) -> Self::Output { + Vector4 { + x: self * rhs.x(), + y: self * rhs.y(), + z: self * rhs.z(), + w: self * rhs.w(), + } + } +} + +impl MulAssign for Vec4 { + fn mul_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) *= rhs + } + } + } +} + +impl Div for &'_ Vec4 { + type Output = Vector4; + + fn div(self, rhs: f32) -> Self::Output { + let inverse = 1.0 / rhs; + Vector4 { + x: self.x() * inverse, + y: self.y() * inverse, + z: self.z() * inverse, + w: self.w() * inverse, + } + } +} + +impl DivAssign for Vec4 { + fn div_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + let inverse = 1.0 / rhs; + unsafe { + for i in 0..4 { + *dest_ptr.add(i) *= inverse + } + } + } +} + +impl Rem for &'_ Vec4 { + type Output = Vector4; + + fn rem(self, rhs: f32) -> Self::Output { + Vector4 { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + z: self.z().rem(rhs), + w: self.w().rem(rhs), + } + } +} + +impl RemAssign for Vec4 { + fn rem_assign(&mut self, rhs: f32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) %= rhs + } + } + } +} + +impl Neg for &'_ Vec4 { + type Output = Vector4; + + fn neg(self) -> Self::Output { + Vector4 { + x: -self.x(), + y: -self.y(), + z: -self.z(), + w: -self.w(), + } + } +} + +impl std::fmt::Debug for Vec4 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec4") + .field("x", &self.x()) + .field("y", &self.y()) + .field("z", &self.z()) + .field("w", &self.w()) + .finish() + } +} + +impl std::fmt::Display for Vec4 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{{{}, {}, {}, {}}}", + self.x(), + self.y(), + self.z(), + self.w() + ) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec4`], which is solely referential, [`Vector4`] is an owning +/// instance. +#[repr(C)] +#[repr(align(16))] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Debug)] +pub struct Vector4 { + /// The X-component of the vector. + pub x: f32, + /// The Y-component of the vector. + pub y: f32, + /// The Z-component of the vector. + pub z: f32, + /// The W-component of the vector. + pub w: f32, +} + +impl Vector4 { + /// A constant for a unit vector in the positive X-direction. + pub const UNIT_X: Vector4 = Vector4::new(1.0, 0.0, 0.0, 0.0); + + /// A constant for a unit vector in the positive Y-direction. + pub const UNIT_Y: Vector4 = Vector4::new(0.0, 1.0, 0.0, 0.0); + + /// A constant for a unit vector in the positive Z-direction. + pub const UNIT_Z: Vector4 = Vector4::new(0.0, 0.0, 1.0, 0.0); + + /// A constant for a unit vector in the positive W-direction. + pub const UNIT_W: Vector4 = Vector4::new(0.0, 0.0, 0.0, 1.0); + + /// A constant for a unit vector in the negative X-direction. + pub const NEG_UNIT_X: Vector4 = Vector4::new(-1.0, 0.0, 0.0, 0.0); + + /// A constant for a unit vector in the negative Y-direction. + pub const NEG_UNIT_Y: Vector4 = Vector4::new(0.0, -1.0, 0.0, 0.0); + + /// A constant for a unit vector in the negative Z-direction. + pub const NEG_UNIT_Z: Vector4 = Vector4::new(0.0, 0.0, -1.0, 0.0); + + /// A constant for a unit vector in the negative W-direction. + pub const NEG_UNIT_W: Vector4 = Vector4::new(0.0, 0.0, 0.0, -1.0); + + /// Constructs this vector from an x, y, z, and w coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + /// * `z` - the z-component + /// * `w` - the w-component + #[inline(always)] + pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self { + Self { x, y, z, w } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: f32) -> Self { + Self::new(v, v, v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[f32]) -> Option { + if slice.len() != 4 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + z: slice[3], + w: slice[4], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[f32]) -> Self { + debug_assert!(slice.len() == 4); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a [`Vec4`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub const fn from_vec4(other: &Vec4) -> Self { + Self { + x: other.x(), + y: other.y(), + z: other.z(), + w: other.w(), + } + } + + /// Constructs this vector from a [`Vec3i`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub fn from_vec4i(other: &Vec4i) -> Self { + Self { + x: other.x() as f32, + y: other.y() as f32, + z: other.z() as f32, + w: other.w() as f32, + } + } + + /// Constructs this vector from a [`Vec3u`] + /// + /// # Arguments + /// + /// * `other` - the other vector + pub fn from_vec4u(other: &Vec4u) -> Self { + Self { + x: other.x() as f32, + y: other.y() as f32, + z: other.z() as f32, + w: other.w() as f32, + } + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 4 [`f32`] values. + pub const unsafe fn from_ptr(ptr: *const f32) -> Self { + Self::new(*ptr, *ptr.add(1), *ptr.add(2), *ptr.add(3)) + } + + /// Returns this vector as a [`Vec4`]. + #[inline(always)] + pub const fn as_vec4(&self) -> &Vec4 { + // SAFETY: + // + // Vector4 is repr(C) and thus points to two contiguous elements + // of type and align of `f32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `f32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const f32, + 4, + )) + } + } + + /// Returns this vector as a mutable [`Vec4`]. + #[inline(always)] + pub fn as_mut_vec4(&mut self) -> &mut Vec4 { + // SAFETY: See explanation in Borrow + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut f32, + 4, + )) + } + } + + /// Returns this vector as a slice of [`f32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[f32] { + self.as_vec4().as_slice() + } + + /// Returns this vector as a mutable slice of [`f32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [f32] { + self.as_mut_vec4().as_mut_slice() + } +} + +impl From<&'_ Vec4> for Vector4 { + #[inline(always)] + fn from(value: &'_ Vec4) -> Self { + value.to_owned() + } +} + +impl From for Vector4 +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl Add for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec4().add(rhs.as_vec4()) + } +} + +impl Add for Vector4 { + type Output = Vector4; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec4()) + } +} + +impl Add<&Vec4> for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn add(self, rhs: &Vec4) -> Self::Output { + self.as_vec4().add(rhs) + } +} + +impl Add<&Vector4> for &'_ Vec4 { + type Output = Vector4; + + #[inline(always)] + fn add(self, rhs: &Vector4) -> Self::Output { + self.add(rhs.as_vec4()) + } +} + +impl Add for &Vec4 { + type Output = Vector4; + + #[inline(always)] + fn add(self, rhs: Vector4) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec4> for Vector4 { + type Output = Vector4; + + fn add(mut self, rhs: &Vec4) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector4> for Vector4 { + type Output = Vector4; + + #[inline(always)] + fn add(self, rhs: &Vector4) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec4()) + } +} + +impl Add for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn add(self, rhs: Vector4) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec4().add(self) + } +} + +impl AddAssign for Vector4 { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec4().add_assign(&rhs) + } +} + +impl AddAssign<&Vector4> for Vector4 { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec4().add_assign(rhs) + } +} + +impl AddAssign<&Vec4> for Vector4 { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec4) { + self.as_mut_vec4().add_assign(rhs) + } +} + +impl Sub for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec4().sub(rhs.as_vec4()) + } +} + +impl Sub for Vector4 { + type Output = Vector4; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub<&Vec4> for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn sub(self, rhs: &Vec4) -> Self::Output { + self.as_vec4().sub(rhs) + } +} + +impl Sub<&Vector4> for &'_ Vec4 { + type Output = Vector4; + + #[inline(always)] + fn sub(self, rhs: &Vector4) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub for &Vec4 { + type Output = Vector4; + + #[inline(always)] + fn sub(self, rhs: Vector4) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub<&Vec4> for Vector4 { + type Output = Vector4; + + fn sub(mut self, rhs: &Vec4) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector4> for Vector4 { + type Output = Vector4; + + #[inline(always)] + fn sub(self, rhs: &Vector4) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn sub(self, rhs: Vector4) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl SubAssign for Vector4 { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec4().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector4> for Vector4 { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec4().sub_assign(rhs) + } +} + +impl SubAssign<&Vec4> for Vector4 { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec4) { + self.as_mut_vec4().sub_assign(rhs) + } +} + +impl Mul for Vector4 { + type Output = Vector4; + + #[inline(always)] + fn mul(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec4().mul_assign(rhs); + self + } +} + +impl Mul for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn mul(self, rhs: f32) -> Self::Output { + self.as_vec4().mul(rhs) + } +} + +impl Mul for f32 { + type Output = Vector4; + + #[inline(always)] + fn mul(self, mut rhs: Vector4) -> Self::Output { + rhs.as_mut_vec4().mul_assign(self); + rhs + } +} + +impl Mul<&Vector4> for f32 { + type Output = Vector4; + + #[inline(always)] + fn mul(self, rhs: &Vector4) -> Self::Output { + rhs.as_vec4().mul(self) + } +} + +impl MulAssign for Vector4 { + #[inline(always)] + fn mul_assign(&mut self, rhs: f32) { + self.as_mut_vec4().mul_assign(rhs) + } +} + +impl Div for Vector4 { + type Output = Vector4; + + #[inline(always)] + fn div(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec4().div_assign(rhs); + self + } +} + +impl Div for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn div(self, rhs: f32) -> Self::Output { + self.as_vec4().div(rhs) + } +} + +impl DivAssign for Vector4 { + #[inline(always)] + fn div_assign(&mut self, rhs: f32) { + self.as_mut_vec4().div_assign(rhs) + } +} + +impl Rem for Vector4 { + type Output = Vector4; + + #[inline(always)] + fn rem(mut self, rhs: f32) -> Self::Output { + self.as_mut_vec4().rem_assign(rhs); + self + } +} + +impl Rem for &Vector4 { + type Output = Vector4; + + #[inline(always)] + fn rem(self, rhs: f32) -> Self::Output { + self.as_vec4().rem(rhs) + } +} + +impl RemAssign for Vector4 { + #[inline(always)] + fn rem_assign(&mut self, rhs: f32) { + self.as_mut_vec4().rem_assign(rhs) + } +} + +impl Deref for Vector4 { + type Target = Vec4; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector4 { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector4 { + #[inline(always)] + fn borrow(&self) -> &Vec4 { + self.as_vec4() + } +} + +impl BorrowMut for Vector4 { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec4 { + self.as_mut_vec4() + } +} + +impl Borrow<[f32]> for Vector4 { + #[inline(always)] + fn borrow(&self) -> &[f32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[f32]> for Vector4 { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [f32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec4 { + type Owned = Vector4; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector4 { + x: self.x(), + y: self.y(), + z: self.z(), + w: self.w(), + } + } +} + +impl std::fmt::Display for Vector4 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}, {}}}", self.x, self.y, self.z, self.w) + } +} + +#[cfg(test)] +mod test { + use crate::cmp::AlmostEq; + + use super::*; + + #[test] + fn test_vec4() { + let vec = Vector4::new(4.0, 2.0, 0.0, 0.0); + + use crate::cmp::AlmostEq; + let magnitude = vec.square_magnitude(); + + assert!(magnitude.almost_eq(&20.0)) + } + + #[test] + fn test_identity() { + let vec = Vector4::new(4.0, 2.0, 0.0, 0.0); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector4::new(4.0, 2.0, 1.0, 0.0); + + for v in vec.iter_mut() { + *v = *v * 2.0 + } + + assert!(vec.x.almost_eq(&8.0), "x = {}", vec.x); + assert!(vec.y.almost_eq(&4.0), "y = {}", vec.y); + assert!(vec.z.almost_eq(&2.0), "z = {}", vec.z); + assert!(vec.w.almost_eq(&0.0), "w = {}", vec.w); + } +} diff --git a/alloy/src/math/vec/vec4i.rs b/alloy/src/math/vec/vec4i.rs new file mode 100644 index 0000000..0dd1d18 --- /dev/null +++ b/alloy/src/math/vec/vec4i.rs @@ -0,0 +1,1106 @@ +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem, + RemAssign, Sub, SubAssign, +}; + +use super::{Vec2i, Vec3i}; + +/// A 4-component view of a vector-like object. +/// +/// [`Vec4i`] objects are to [`Vector4i`] as [`str`] is to [`String`]; that is to +/// say that [`Vec4i`] objects represent an immutable view of the owning +/// [`Vector4i`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd, Eq, Ord)] +pub struct Vec4i([i32]); + +impl Vec4i { + /// Forms a reference to a [`Vec4i`] from a slice of [`i32`]. + /// + /// This requires that `slice.len() == 4`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`i32`]s. + pub const fn from_slice(slice: &[i32]) -> Option<&Self> { + if slice.len() == 4 { + // SAFETY: Vec4 is transparent, and implemented directly in terms of a + // slice of i32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec4i`] from a mutable slice of [`i32`]. + /// + /// This requires that `slice.len() == 4`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`i32`]s. + pub fn from_mut_slice(slice: &mut [i32]) -> Option<&mut Self> { + if slice.len() == 4 { + // SAFETY: Vec4 is transparent, and implemented directly in terms of a + // slice of i32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec4i`] from a slice of [`i32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`i32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[i32]) -> &Self { + debug_assert!(slice.len() == 4); + std::mem::transmute(slice) + } + + /// Forms a mutable reference to a [`Vec4i`] from a slice of [`i32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`i32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [i32]) -> &mut Self { + debug_assert!(slice.len() == 4); + std::mem::transmute(slice) + } + + /// Forms a reference to a [`Vec2i`] from a pointer to a contiguous sequence + /// of at least two [`i32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`i32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const i32) -> &'a Vec4i { + Vec4i::from_slice_unchecked(std::slice::from_raw_parts(ptr, 4)) + } + + /// Forms a mutable reference to a [`Vec3i`] from a pointer to a contiguous + /// sequence of at least two [`i32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`i32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut i32) -> &'a mut Vec4i { + Vec4i::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 4)) + } + + /// Returns this [`Vec4i`] as a slice of [`i32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[i32] { + &self.0 + } + + /// Returns this [`Vec4i`] as a mutable slice of [`i32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [i32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 4-component vector. + #[inline(always)] + pub fn x(&self) -> i32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 4-component vector. + #[inline(always)] + pub fn y(&self) -> i32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns the Z-coordinate of this 4-component vector. + #[inline(always)] + pub fn z(&self) -> i32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(2) } + } + + /// Returns the W-coordinate of this 4-component vector. + #[inline(always)] + pub fn w(&self) -> i32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(3) } + } + + /// Returns the xy coordinates of this vector as a [`Vec2i`]. + #[inline(always)] + pub const fn xy(&self) -> &Vec2i { + unsafe { Vec2i::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec2i`]. + #[inline(always)] + pub const fn yz(&self) -> &Vec2i { + unsafe { Vec2i::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns the zw coordinates of this vector as a [`Vec2i`]. + #[inline(always)] + pub const fn zw(&self) -> &Vec2i { + unsafe { Vec2i::from_ptr_unchecked(self.0.as_ptr().add(2)) } + } + + /// Returns the xyz coordinates of this vector as a [`Vec2i`]. + #[inline(always)] + pub const fn xyz(&self) -> &Vec3i { + unsafe { Vec3i::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec2i`]. + #[inline(always)] + pub const fn yzw(&self) -> &Vec3i { + unsafe { Vec3i::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns a mutable reference to the X-coordinate of this 3-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 3-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Returns a mutable reference to the Z-coordinate of this 3-component vector. + #[inline(always)] + pub fn z_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr().add(2) } + } + + /// Returns a mutable reference to the W-coordinate of this 3-component vector. + #[inline(always)] + pub fn w_mut(&mut self) -> &mut i32 { + unsafe { &mut *self.0.as_mut_ptr().add(3) } + } + + /// Returns a mutable reference to the xy coordinates of this vector. + #[inline(always)] + pub fn xy_mut(&mut self) -> &mut Vec2i { + unsafe { Vec2i::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn yz_mut(&mut self) -> &mut Vec2i { + unsafe { Vec2i::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Returns a mutable reference to the zw coordinates of this vector. + #[inline(always)] + pub fn zw_mut(&mut self) -> &mut Vec2i { + unsafe { Vec2i::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(2)) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn xyz_mut(&mut self) -> &mut Vec3i { + unsafe { Vec3i::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the zw coordinates of this vector. + #[inline(always)] + pub fn yzw_mut(&mut self) -> &mut Vec3i { + unsafe { Vec3i::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: i32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: i32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets the z-component + /// + /// # Arguments + /// + /// * `z` - theZ-component + #[inline(always)] + pub fn set_z(&mut self, z: i32) { + unsafe { *self.0.as_mut_ptr().add(2) = z } + } + + /// Sets the w-component + /// + /// # Arguments + /// + /// * `w` - the W-component + #[inline(always)] + pub fn set_w(&mut self, w: i32) { + unsafe { *self.0.as_mut_ptr().add(3) = w } + } + + /// Sets the X and Y components of this vector + /// + /// # Arguments + /// + /// * `xy` - the X and Y components of the [`Vec4i`] + #[inline(always)] + pub fn set_xy(&mut self, xy: &Vec2i) { + self.xy_mut().set(xy) + } + + /// Sets the Y and Z components of this vector + /// + /// # Arguments + /// + /// * `yz` - the Y and Z components of the [`Vec4i`] + #[inline(always)] + pub fn set_yz(&mut self, yz: &Vec2i) { + self.yz_mut().set(yz) + } + + /// Sets the Z and W components of this vector + /// + /// # Arguments + /// + /// * `zw` - the Z and W components of the [`Vec4i`] + #[inline(always)] + pub fn set_zw(&mut self, zw: &Vec2i) { + self.zw_mut().set(zw) + } + + /// Sets the X, Y, and Z components of this vector + /// + /// # Arguments + /// + /// * `xyz` - the X, Y, and Z components of the [`Vec4i`]` + #[inline(always)] + pub fn set_xyz(&mut self, xyz: &Vec3i) { + self.xyz_mut().set(xyz) + } + + /// Sets the Y, Z and W components of this vector + /// + /// # Arguments + /// + /// * `yzw` - the Y, Z, and W components of the [`Vec4i`] + #[inline(always)] + pub fn set_yzw(&mut self, yzw: &Vec3i) { + self.yzw_mut().set(yzw) + } +} + +impl Index for Vec4i +where + I: std::slice::SliceIndex<[i32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec4i +where + I: std::slice::SliceIndex<[i32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec4i { + type Target = [i32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec4i { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[i32]> for Vec4i { + #[inline(always)] + fn as_ref(&self) -> &[i32] { + &self.0 + } +} + +impl AsMut<[i32]> for Vec4i { + #[inline(always)] + fn as_mut(&mut self) -> &mut [i32] { + &mut self.0 + } +} + +impl Add for &'_ Vec4i { + type Output = Vector4i; + + fn add(self, rhs: Self) -> Self::Output { + Vector4i { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + z: self.z() + rhs.z(), + w: self.w() + rhs.w(), + } + } +} + +impl AddAssign<&Vec4i> for Vec4i { + fn add_assign(&mut self, rhs: &Vec4i) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + } +} + +impl Sub for &'_ Vec4i { + type Output = Vector4i; + + fn sub(self, rhs: Self) -> Self::Output { + Vector4i { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + z: self.z() - rhs.z(), + w: self.w() - rhs.w(), + } + } +} + +impl SubAssign<&Vec4i> for Vec4i { + fn sub_assign(&mut self, rhs: &Vec4i) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + } +} + +impl Mul for &'_ Vec4i { + type Output = Vector4i; + + fn mul(self, rhs: i32) -> Self::Output { + Vector4i { + x: self.x() * rhs, + y: self.y() * rhs, + z: self.z() * rhs, + w: self.w() * rhs, + } + } +} + +impl Mul<&'_ Vec4i> for i32 { + type Output = Vector4i; + + fn mul(self, rhs: &'_ Vec4i) -> Self::Output { + Vector4i { + x: self * rhs.x(), + y: self * rhs.y(), + z: self * rhs.z(), + w: self * rhs.w(), + } + } +} + +impl MulAssign for Vec4i { + fn mul_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) *= rhs + } + } + } +} + +impl Div for &'_ Vec4i { + type Output = Vector4i; + + fn div(self, rhs: i32) -> Self::Output { + Vector4i { + x: self.x() / rhs, + y: self.y() / rhs, + z: self.z() / rhs, + w: self.w() / rhs, + } + } +} + +impl DivAssign for Vec4i { + fn div_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) /= rhs + } + } + } +} + +impl Rem for &'_ Vec4i { + type Output = Vector4i; + + fn rem(self, rhs: i32) -> Self::Output { + Vector4i { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + z: self.z().rem(rhs), + w: self.w().rem(rhs), + } + } +} + +impl RemAssign for Vec4i { + fn rem_assign(&mut self, rhs: i32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) %= rhs + } + } + } +} + +impl Neg for &'_ Vec4i { + type Output = Vector4i; + + fn neg(self) -> Self::Output { + Vector4i { + x: -self.x(), + y: -self.y(), + z: -self.z(), + w: -self.w(), + } + } +} + +impl std::fmt::Debug for Vec4i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec4i") + .field("x", &self.x()) + .field("y", &self.y()) + .field("z", &self.z()) + .field("w", &self.w()) + .finish() + } +} + +impl std::fmt::Display for Vec4i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{{{}, {}, {}, {}}}", + self.x(), + self.y(), + self.z(), + self.w() + ) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec4i`], which is solely referential, [`Vector4i`] is an owning +/// instance. +#[repr(C)] +#[repr(align(16))] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] +pub struct Vector4i { + /// The X-component of the vector. + pub x: i32, + /// The Y-component of the vector. + pub y: i32, + /// The Z-component of the vector. + pub z: i32, + /// The W-component of the vector. + pub w: i32, +} + +impl Vector4i { + /// Constructs this vector from an x, y, z, and w coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + /// * `z` - the z-component + /// * `w` - the w-component + #[inline(always)] + pub const fn new(x: i32, y: i32, z: i32, w: i32) -> Self { + Self { x, y, z, w } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: i32) -> Self { + Self::new(v, v, v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[i32]) -> Option { + if slice.len() != 4 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + z: slice[3], + w: slice[4], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[i32]) -> Self { + debug_assert!(slice.len() == 4); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 4 [`i32`] values. + pub const unsafe fn from_ptr(ptr: *const i32) -> Self { + Self::new(*ptr, *ptr.add(1), *ptr.add(2), *ptr.add(3)) + } + + /// Returns this vector as a [`Vec4i`]. + #[inline(always)] + pub const fn as_vec4(&self) -> &Vec4i { + // SAFETY: + // + // Vector4i is repr(C) and thus points to two contiguous elements + // of type and align of `i32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `i32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const i32, + 4, + )) + } + } + + /// Returns this vector as a mutable [`Vec4i`]. + #[inline(always)] + pub fn as_mut_vec4(&mut self) -> &mut Vec4i { + // SAFETY: See explanation in Borrow + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut i32, + 4, + )) + } + } + + /// Returns this vector as a slice of [`i32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[i32] { + self.as_vec4().as_slice() + } + + /// Returns this vector as a mutable slice of [`i32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [i32] { + self.as_mut_vec4().as_mut_slice() + } +} + +impl From<&'_ Vec4i> for Vector4i { + #[inline(always)] + fn from(value: &'_ Vec4i) -> Self { + value.to_owned() + } +} + +impl From for Vector4i +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl Add for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec4().add(rhs.as_vec4()) + } +} + +impl Add for Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec4()) + } +} + +impl Add<&Vec4i> for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn add(self, rhs: &Vec4i) -> Self::Output { + self.as_vec4().add(rhs) + } +} + +impl Add<&Vector4i> for &'_ Vec4i { + type Output = Vector4i; + + #[inline(always)] + fn add(self, rhs: &Vector4i) -> Self::Output { + self.add(rhs.as_vec4()) + } +} + +impl Add for &Vec4i { + type Output = Vector4i; + + #[inline(always)] + fn add(self, rhs: Vector4i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec4i> for Vector4i { + type Output = Vector4i; + + fn add(mut self, rhs: &Vec4i) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector4i> for Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn add(self, rhs: &Vector4i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec4()) + } +} + +impl Add for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn add(self, rhs: Vector4i) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec4().add(self) + } +} + +impl AddAssign for Vector4i { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec4().add_assign(&rhs) + } +} + +impl AddAssign<&Vector4i> for Vector4i { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec4().add_assign(rhs) + } +} + +impl AddAssign<&Vec4i> for Vector4i { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec4i) { + self.as_mut_vec4().add_assign(rhs) + } +} + +impl Sub for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec4().sub(rhs.as_vec4()) + } +} + +impl Sub for Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub<&Vec4i> for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn sub(self, rhs: &Vec4i) -> Self::Output { + self.as_vec4().sub(rhs) + } +} + +impl Sub<&Vector4i> for &'_ Vec4i { + type Output = Vector4i; + + #[inline(always)] + fn sub(self, rhs: &Vector4i) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub for &Vec4i { + type Output = Vector4i; + + #[inline(always)] + fn sub(self, rhs: Vector4i) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub<&Vec4i> for Vector4i { + type Output = Vector4i; + + fn sub(mut self, rhs: &Vec4i) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector4i> for Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn sub(self, rhs: &Vector4i) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn sub(self, rhs: Vector4i) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl SubAssign for Vector4i { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec4().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector4i> for Vector4i { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec4().sub_assign(rhs) + } +} + +impl SubAssign<&Vec4i> for Vector4i { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec4i) { + self.as_mut_vec4().sub_assign(rhs) + } +} + +impl Mul for Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn mul(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec4().mul_assign(rhs); + self + } +} + +impl Mul for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn mul(self, rhs: i32) -> Self::Output { + self.as_vec4().mul(rhs) + } +} + +impl Mul for i32 { + type Output = Vector4i; + + #[inline(always)] + fn mul(self, mut rhs: Vector4i) -> Self::Output { + rhs.as_mut_vec4().mul_assign(self); + rhs + } +} + +impl Mul<&Vector4i> for i32 { + type Output = Vector4i; + + #[inline(always)] + fn mul(self, rhs: &Vector4i) -> Self::Output { + rhs.as_vec4().mul(self) + } +} + +impl MulAssign for Vector4i { + #[inline(always)] + fn mul_assign(&mut self, rhs: i32) { + self.as_mut_vec4().mul_assign(rhs) + } +} + +impl Div for Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn div(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec4().div_assign(rhs); + self + } +} + +impl Div for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn div(self, rhs: i32) -> Self::Output { + self.as_vec4().div(rhs) + } +} + +impl DivAssign for Vector4i { + #[inline(always)] + fn div_assign(&mut self, rhs: i32) { + self.as_mut_vec4().div_assign(rhs) + } +} + +impl Rem for Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn rem(mut self, rhs: i32) -> Self::Output { + self.as_mut_vec4().rem_assign(rhs); + self + } +} + +impl Rem for &Vector4i { + type Output = Vector4i; + + #[inline(always)] + fn rem(self, rhs: i32) -> Self::Output { + self.as_vec4().rem(rhs) + } +} + +impl RemAssign for Vector4i { + #[inline(always)] + fn rem_assign(&mut self, rhs: i32) { + self.as_mut_vec4().rem_assign(rhs) + } +} + +impl Deref for Vector4i { + type Target = Vec4i; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector4i { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector4i { + #[inline(always)] + fn borrow(&self) -> &Vec4i { + self.as_vec4() + } +} + +impl BorrowMut for Vector4i { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec4i { + self.as_mut_vec4() + } +} + +impl Borrow<[i32]> for Vector4i { + #[inline(always)] + fn borrow(&self) -> &[i32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[i32]> for Vector4i { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [i32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec4i { + type Owned = Vector4i; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector4i { + x: self.x(), + y: self.y(), + z: self.z(), + w: self.w(), + } + } +} + +impl std::fmt::Display for Vector4i { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}, {}}}", self.x, self.y, self.z, self.w) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_identity() { + let vec = Vector4i::new(4, 2, 0, 0); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector4i::new(4, 2, 1, 0); + + for v in vec.iter_mut() { + *v = *v * 2 + } + + assert_eq!(vec.x, 8); + assert_eq!(vec.y, 4); + assert_eq!(vec.z, 2); + assert_eq!(vec.w, 0); + } +} diff --git a/alloy/src/math/vec/vec4u.rs b/alloy/src/math/vec/vec4u.rs new file mode 100644 index 0000000..99a49fc --- /dev/null +++ b/alloy/src/math/vec/vec4u.rs @@ -0,0 +1,1093 @@ +use std::borrow::{Borrow, BorrowMut}; +use std::ops::{ + Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Rem, RemAssign, + Sub, SubAssign, +}; + +use super::{Vec2u, Vec3u}; + +/// A 4-component view of a vector-like object. +/// +/// [`Vec4u`] objects are to [`Vector4u`] as [`str`] is to [`String`]; that is to +/// say that [`Vec4u`] objects represent an immutable view of the owning +/// [`Vector4u`] counter-part. +#[repr(transparent)] +#[derive(PartialEq, PartialOrd, Eq, Ord)] +pub struct Vec4u([u32]); + +impl Vec4u { + /// Forms a reference to a [`Vec4u`] from a slice of [`u32`]. + /// + /// This requires that `slice.len() == 4`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`u32`]s. + pub const fn from_slice(slice: &[u32]) -> Option<&Self> { + if slice.len() == 4 { + // SAFETY: Vec4 is transparent, and implemented directly in terms of a + // slice of u32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a mutable reference to a [`Vec4u`] from a mutable slice of [`u32`]. + /// + /// This requires that `slice.len() == 4`, otherwise this returns [`None`]. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`u32`]s. + pub fn from_mut_slice(slice: &mut [u32]) -> Option<&mut Self> { + if slice.len() == 4 { + // SAFETY: Vec4 is transparent, and implemented directly in terms of a + // slice of u32s. The representation is the same, and thus valid. + // This is implemented symmetrically to `OsStr`. + Some(unsafe { std::mem::transmute(slice) }) + } else { + None + } + } + + /// Forms a reference to a [`Vec4u`] from a slice of [`u32`] that is assumed to + /// contain two values. + /// + /// # Arguments + /// + /// * `slice` - the slice of [`u32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[u32]) -> &Self { + debug_assert!(slice.len() == 4); + std::mem::transmute(slice) + } + + /// Forms a mutable reference to a [`Vec4u`] from a slice of [`u32`] that is + /// assumed to contain two values. + /// + /// # Arguments + /// + /// * `slice` - the mutable slice of [`u32`]s. + /// + /// # Safety + /// + /// `slice.len()` must be equal to `2`. + #[inline(always)] + pub unsafe fn from_mut_slice_unchecked(slice: &mut [u32]) -> &mut Self { + debug_assert!(slice.len() == 4); + std::mem::transmute(slice) + } + + /// Forms a reference to a [`Vec2u`] from a pointer to a contiguous sequence + /// of at least two [`u32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`u32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub const unsafe fn from_ptr_unchecked<'a>(ptr: *const u32) -> &'a Vec4u { + Vec4u::from_slice_unchecked(std::slice::from_raw_parts(ptr, 4)) + } + + /// Forms a mutable reference to a [`Vec3u`] from a pointer to a contiguous + /// sequence of at least two [`u32`]s. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to a sequence of [`u32`] values + /// + /// # Safety + /// + /// `ptr` must point to an allocated object that references at least two + /// entries + #[inline(always)] + pub unsafe fn from_mut_ptr_unchecked<'a>(ptr: *mut u32) -> &'a mut Vec4u { + Vec4u::from_mut_slice_unchecked(std::slice::from_raw_parts_mut(ptr, 4)) + } + + /// Returns this [`Vec4u`] as a slice of [`u32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[u32] { + &self.0 + } + + /// Returns this [`Vec4u`] as a mutable slice of [`u32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [u32] { + &mut self.0 + } + + /// Returns the X-coordinate of this 4-component vector. + #[inline(always)] + pub fn x(&self) -> u32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr() } + } + + /// Returns the Y-coordinate of this 4-component vector. + #[inline(always)] + pub fn y(&self) -> u32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(1) } + } + + /// Returns the Z-coordinate of this 4-component vector. + #[inline(always)] + pub fn z(&self) -> u32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(2) } + } + + /// Returns the W-coordinate of this 4-component vector. + #[inline(always)] + pub fn w(&self) -> u32 { + // SAFETY: Vec4 being of size-4 is an internal invariant + unsafe { *self.0.as_ptr().add(3) } + } + + /// Returns the xy coordinates of this vector as a [`Vec2u`]. + #[inline(always)] + pub const fn xy(&self) -> &Vec2u { + unsafe { Vec2u::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec2u`]. + #[inline(always)] + pub const fn yz(&self) -> &Vec2u { + unsafe { Vec2u::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns the zw coordinates of this vector as a [`Vec2u`]. + #[inline(always)] + pub const fn zw(&self) -> &Vec2u { + unsafe { Vec2u::from_ptr_unchecked(self.0.as_ptr().add(2)) } + } + + /// Returns the xyz coordinates of this vector as a [`Vec2u`]. + #[inline(always)] + pub const fn xyz(&self) -> &Vec3u { + unsafe { Vec3u::from_ptr_unchecked(self.0.as_ptr()) } + } + + /// Returns the yz coordinates of this vector as a [`Vec2u`]. + #[inline(always)] + pub const fn yzw(&self) -> &Vec3u { + unsafe { Vec3u::from_ptr_unchecked(self.0.as_ptr().add(1)) } + } + + /// Returns a mutable reference to the X-coordinate of this 3-component vector. + #[inline(always)] + pub fn x_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr() } + } + + /// Returns a mutable reference to the Y-coordinate of this 3-component vector. + #[inline(always)] + pub fn y_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr().add(1) } + } + + /// Returns a mutable reference to the Z-coordinate of this 3-component vector. + #[inline(always)] + pub fn z_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr().add(2) } + } + + /// Returns a mutable reference to the W-coordinate of this 3-component vector. + #[inline(always)] + pub fn w_mut(&mut self) -> &mut u32 { + unsafe { &mut *self.0.as_mut_ptr().add(3) } + } + + /// Returns a mutable reference to the xy coordinates of this vector. + #[inline(always)] + pub fn xy_mut(&mut self) -> &mut Vec2u { + unsafe { Vec2u::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn yz_mut(&mut self) -> &mut Vec2u { + unsafe { Vec2u::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Returns a mutable reference to the zw coordinates of this vector. + #[inline(always)] + pub fn zw_mut(&mut self) -> &mut Vec2u { + unsafe { Vec2u::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(2)) } + } + + /// Returns a mutable reference to the yz coordinates of this vector. + #[inline(always)] + pub fn xyz_mut(&mut self) -> &mut Vec3u { + unsafe { Vec3u::from_mut_ptr_unchecked(self.0.as_mut_ptr()) } + } + + /// Returns a mutable reference to the zw coordinates of this vector. + #[inline(always)] + pub fn yzw_mut(&mut self) -> &mut Vec3u { + unsafe { Vec3u::from_mut_ptr_unchecked(self.0.as_mut_ptr().add(1)) } + } + + /// Sets the x-component + /// + /// # Arguments + /// + /// * `x` - the X-component + #[inline(always)] + pub fn set_x(&mut self, x: u32) { + unsafe { *self.0.as_mut_ptr() = x } + } + + /// Sets the y-component + /// + /// # Arguments + /// + /// * `y` - the Y-component + #[inline(always)] + pub fn set_y(&mut self, y: u32) { + unsafe { *self.0.as_mut_ptr().add(1) = y } + } + + /// Sets the z-component + /// + /// # Arguments + /// + /// * `z` - theZ-component + #[inline(always)] + pub fn set_z(&mut self, z: u32) { + unsafe { *self.0.as_mut_ptr().add(2) = z } + } + + /// Sets the w-component + /// + /// # Arguments + /// + /// * `w` - the W-component + #[inline(always)] + pub fn set_w(&mut self, w: u32) { + unsafe { *self.0.as_mut_ptr().add(3) = w } + } + + /// Sets the X and Y components of this vector + /// + /// # Arguments + /// + /// * `xy` - the X and Y components of the [`Vec4u`] + #[inline(always)] + pub fn set_xy(&mut self, xy: &Vec2u) { + self.xy_mut().set(xy) + } + + /// Sets the Y and Z components of this vector + /// + /// # Arguments + /// + /// * `yz` - the Y and Z components of the [`Vec4u`] + #[inline(always)] + pub fn set_yz(&mut self, yz: &Vec2u) { + self.yz_mut().set(yz) + } + + /// Sets the Z and W components of this vector + /// + /// # Arguments + /// + /// * `zw` - the Z and W components of the [`Vec4u`] + #[inline(always)] + pub fn set_zw(&mut self, zw: &Vec2u) { + self.zw_mut().set(zw) + } + + /// Sets the X, Y, and Z components of this vector + /// + /// # Arguments + /// + /// * `xyz` - the X, Y, and Z components of the [`Vec4u`]` + #[inline(always)] + pub fn set_xyz(&mut self, xyz: &Vec3u) { + self.xyz_mut().set(xyz) + } + + /// Sets the Y, Z and W components of this vector + /// + /// # Arguments + /// + /// * `yzw` - the Y, Z, and W components of the [`Vec4u`] + #[inline(always)] + pub fn set_yzw(&mut self, yzw: &Vec3u) { + self.yzw_mut().set(yzw) + } +} + +impl Index for Vec4u +where + I: std::slice::SliceIndex<[u32]>, +{ + type Output = I::Output; + + #[inline(always)] + fn index(&self, index: I) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for Vec4u +where + I: std::slice::SliceIndex<[u32]>, +{ + #[inline(always)] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Deref for Vec4u { + type Target = [u32]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Vec4u { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl AsRef<[u32]> for Vec4u { + #[inline(always)] + fn as_ref(&self) -> &[u32] { + &self.0 + } +} + +impl AsMut<[u32]> for Vec4u { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u32] { + &mut self.0 + } +} + +impl Add for &'_ Vec4u { + type Output = Vector4u; + + fn add(self, rhs: Self) -> Self::Output { + Vector4u { + x: self.x() + rhs.x(), + y: self.y() + rhs.y(), + z: self.z() + rhs.z(), + w: self.w() + rhs.w(), + } + } +} + +impl AddAssign<&Vec4u> for Vec4u { + fn add_assign(&mut self, rhs: &Vec4u) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + } +} + +impl Sub for &'_ Vec4u { + type Output = Vector4u; + + fn sub(self, rhs: Self) -> Self::Output { + Vector4u { + x: self.x() - rhs.x(), + y: self.y() - rhs.y(), + z: self.z() - rhs.z(), + w: self.w() - rhs.w(), + } + } +} + +impl SubAssign<&Vec4u> for Vec4u { + fn sub_assign(&mut self, rhs: &Vec4u) { + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + } +} + +impl Mul for &'_ Vec4u { + type Output = Vector4u; + + fn mul(self, rhs: u32) -> Self::Output { + Vector4u { + x: self.x() * rhs, + y: self.y() * rhs, + z: self.z() * rhs, + w: self.w() * rhs, + } + } +} + +impl Mul<&'_ Vec4u> for u32 { + type Output = Vector4u; + + fn mul(self, rhs: &'_ Vec4u) -> Self::Output { + Vector4u { + x: self * rhs.x(), + y: self * rhs.y(), + z: self * rhs.z(), + w: self * rhs.w(), + } + } +} + +impl MulAssign for Vec4u { + fn mul_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) *= rhs + } + } + } +} + +impl Div for &'_ Vec4u { + type Output = Vector4u; + + fn div(self, rhs: u32) -> Self::Output { + Vector4u { + x: self.x() / rhs, + y: self.y() / rhs, + z: self.z() / rhs, + w: self.w() / rhs, + } + } +} + +impl DivAssign for Vec4u { + fn div_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) /= rhs + } + } + } +} + +impl Rem for &'_ Vec4u { + type Output = Vector4u; + + fn rem(self, rhs: u32) -> Self::Output { + Vector4u { + x: self.x().rem(rhs), + y: self.y().rem(rhs), + z: self.z().rem(rhs), + w: self.w().rem(rhs), + } + } +} + +impl RemAssign for Vec4u { + fn rem_assign(&mut self, rhs: u32) { + let dest_ptr = self.0.as_mut_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) %= rhs + } + } + } +} + +impl std::fmt::Debug for Vec4u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Vec4u") + .field("x", &self.x()) + .field("y", &self.y()) + .field("z", &self.z()) + .field("w", &self.w()) + .finish() + } +} + +impl std::fmt::Display for Vec4u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{{{}, {}, {}, {}}}", + self.x(), + self.y(), + self.z(), + self.w() + ) + } +} + +/// An owning representation of a 2-dimensional Vector object. +/// +/// Unlike [`Vec4u`], which is solely referential, [`Vector4u`] is an owning +/// instance. +#[repr(C)] +#[repr(align(16))] +#[derive(Clone, Copy, Default, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] +pub struct Vector4u { + /// The X-component of the vector. + pub x: u32, + /// The Y-component of the vector. + pub y: u32, + /// The Z-component of the vector. + pub z: u32, + /// The W-component of the vector. + pub w: u32, +} + +impl Vector4u { + /// Constructs this vector from an x, y, z, and w coordinate. + /// + /// # Arguments + /// + /// * `x` - the x-component + /// * `y` - the y-component + /// * `z` - the z-component + /// * `w` - the w-component + #[inline(always)] + pub const fn new(x: u32, y: u32, z: u32, w: u32) -> Self { + Self { x, y, z, w } + } + + /// Constructs this vector with a uniform value `v`. + /// + /// # Arguments + /// + /// * `v` - the value to uniformly apply + #[inline(always)] + pub const fn uniform(v: u32) -> Self { + Self::new(v, v, v, v) + } + + /// Constructs this vector from a slice of floats. + /// + /// This will return [`None`] if `slice.len()` is not equal to 2. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + pub const fn from_slice(slice: &[u32]) -> Option { + if slice.len() != 4 { + None + } else { + Some(Self { + x: slice[0], + y: slice[1], + z: slice[3], + w: slice[4], + }) + } + } + + /// Constructs this vector from a slice of floats. + /// + /// # Arguments + /// + /// * `slice` - the slice to read from + /// + /// # Safety + /// + /// `slice.len()` must be greater or equal to `2`, otherwise this will + /// access an out-of-bounds entry and `panic`. + #[inline(always)] + pub const unsafe fn from_slice_unchecked(slice: &[u32]) -> Self { + debug_assert!(slice.len() == 4); + Self::from_ptr(slice.as_ptr()) + } + + /// Constructs this vector from a pointer to floating point values. + /// + /// # Arguments + /// + /// * `ptr` - the pointer to the start of a contiguous sequence of floats + /// + /// # Safety + /// + /// This function requires that `ptr` be non-null and point to the start of a + /// contiguous sequence of 3 [`u32`] values. + pub const unsafe fn from_ptr(ptr: *const u32) -> Self { + Self::new(*ptr, *ptr.add(1), *ptr.add(2), *ptr.add(3)) + } + + /// Returns this vector as a [`Vec4u`]. + #[inline(always)] + pub const fn as_vec4(&self) -> &Vec4u { + // SAFETY: + // + // Vector4u is repr(C) and thus points to two contiguous elements + // of type and align of `u32`. The only pointer capable of accessing both + // entries within its memory region is a pointer to itself (`*const _`). + // Thus, we alias this to `u32` -- which under `repr(C)` points to the + // first element, and has proper reachability into its neighbor-element. + unsafe { + std::mem::transmute(std::slice::from_raw_parts( + self as *const _ as *const u32, + 4, + )) + } + } + + /// Returns this vector as a mutable [`Vec4u`]. + #[inline(always)] + pub fn as_mut_vec4(&mut self) -> &mut Vec4u { + // SAFETY: See explanation in Borrow + unsafe { + std::mem::transmute(std::slice::from_raw_parts_mut( + self as *mut _ as *mut u32, + 4, + )) + } + } + + /// Returns this vector as a slice of [`u32`]. + #[inline(always)] + pub const fn as_slice(&self) -> &[u32] { + self.as_vec4().as_slice() + } + + /// Returns this vector as a mutable slice of [`u32`]. + #[inline(always)] + pub fn as_mut_slice(&mut self) -> &mut [u32] { + self.as_mut_vec4().as_mut_slice() + } +} + +impl From<&'_ Vec4u> for Vector4u { + #[inline(always)] + fn from(value: &'_ Vec4u) -> Self { + value.to_owned() + } +} + +impl From for Vector4u +where + Vec: AsRef, +{ + #[inline(always)] + fn from(value: Vec) -> Self { + value.as_ref().to_owned() + } +} + +impl Add for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.as_vec4().add(rhs.as_vec4()) + } +} + +impl Add for Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn add(self, rhs: Self) -> Self::Output { + self.add(rhs.as_vec4()) + } +} + +impl Add<&Vec4u> for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn add(self, rhs: &Vec4u) -> Self::Output { + self.as_vec4().add(rhs) + } +} + +impl Add<&Vector4u> for &'_ Vec4u { + type Output = Vector4u; + + #[inline(always)] + fn add(self, rhs: &Vector4u) -> Self::Output { + self.add(rhs.as_vec4()) + } +} + +impl Add for &Vec4u { + type Output = Vector4u; + + #[inline(always)] + fn add(self, rhs: Vector4u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self) + } +} + +impl Add<&Vec4u> for Vector4u { + type Output = Vector4u; + + fn add(mut self, rhs: &Vec4u) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) += *src_ptr.add(i) + } + } + self + } +} + +impl Add<&Vector4u> for Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn add(self, rhs: &Vector4u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.add(self.as_vec4()) + } +} + +impl Add for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn add(self, rhs: Vector4u) -> Self::Output { + // Addition is commutative, so reordering operations is safe + rhs.as_vec4().add(self) + } +} + +impl AddAssign for Vector4u { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + self.as_mut_vec4().add_assign(&rhs) + } +} + +impl AddAssign<&Vector4u> for Vector4u { + #[inline(always)] + fn add_assign(&mut self, rhs: &Self) { + self.as_mut_vec4().add_assign(rhs) + } +} + +impl AddAssign<&Vec4u> for Vector4u { + #[inline(always)] + fn add_assign(&mut self, rhs: &Vec4u) { + self.as_mut_vec4().add_assign(rhs) + } +} + +impl Sub for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.as_vec4().sub(rhs.as_vec4()) + } +} + +impl Sub for Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub<&Vec4u> for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn sub(self, rhs: &Vec4u) -> Self::Output { + self.as_vec4().sub(rhs) + } +} + +impl Sub<&Vector4u> for &'_ Vec4u { + type Output = Vector4u; + + #[inline(always)] + fn sub(self, rhs: &Vector4u) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub for &Vec4u { + type Output = Vector4u; + + #[inline(always)] + fn sub(self, rhs: Vector4u) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub<&Vec4u> for Vector4u { + type Output = Vector4u; + + fn sub(mut self, rhs: &Vec4u) -> Self::Output { + // Repurpose 'self' for the output, to save space (1 less lifetime) + let dest_ptr = self.0.as_mut_ptr(); + let src_ptr = rhs.0.as_ptr(); + + unsafe { + for i in 0..4 { + *dest_ptr.add(i) -= *src_ptr.add(i) + } + } + self + } +} + +impl Sub<&Vector4u> for Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn sub(self, rhs: &Vector4u) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl Sub for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn sub(self, rhs: Vector4u) -> Self::Output { + self.sub(rhs.as_vec4()) + } +} + +impl SubAssign for Vector4u { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + self.as_mut_vec4().sub_assign(&rhs) + } +} + +impl SubAssign<&Vector4u> for Vector4u { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Self) { + self.as_mut_vec4().sub_assign(rhs) + } +} + +impl SubAssign<&Vec4u> for Vector4u { + #[inline(always)] + fn sub_assign(&mut self, rhs: &Vec4u) { + self.as_mut_vec4().sub_assign(rhs) + } +} + +impl Mul for Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn mul(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec4().mul_assign(rhs); + self + } +} + +impl Mul for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn mul(self, rhs: u32) -> Self::Output { + self.as_vec4().mul(rhs) + } +} + +impl Mul for u32 { + type Output = Vector4u; + + #[inline(always)] + fn mul(self, mut rhs: Vector4u) -> Self::Output { + rhs.as_mut_vec4().mul_assign(self); + rhs + } +} + +impl Mul<&Vector4u> for u32 { + type Output = Vector4u; + + #[inline(always)] + fn mul(self, rhs: &Vector4u) -> Self::Output { + rhs.as_vec4().mul(self) + } +} + +impl MulAssign for Vector4u { + #[inline(always)] + fn mul_assign(&mut self, rhs: u32) { + self.as_mut_vec4().mul_assign(rhs) + } +} + +impl Div for Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn div(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec4().div_assign(rhs); + self + } +} + +impl Div for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn div(self, rhs: u32) -> Self::Output { + self.as_vec4().div(rhs) + } +} + +impl DivAssign for Vector4u { + #[inline(always)] + fn div_assign(&mut self, rhs: u32) { + self.as_mut_vec4().div_assign(rhs) + } +} + +impl Rem for Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn rem(mut self, rhs: u32) -> Self::Output { + self.as_mut_vec4().rem_assign(rhs); + self + } +} + +impl Rem for &Vector4u { + type Output = Vector4u; + + #[inline(always)] + fn rem(self, rhs: u32) -> Self::Output { + self.as_vec4().rem(rhs) + } +} + +impl RemAssign for Vector4u { + #[inline(always)] + fn rem_assign(&mut self, rhs: u32) { + self.as_mut_vec4().rem_assign(rhs) + } +} + +impl Deref for Vector4u { + type Target = Vec4u; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for Vector4u { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + +impl Borrow for Vector4u { + #[inline(always)] + fn borrow(&self) -> &Vec4u { + self.as_vec4() + } +} + +impl BorrowMut for Vector4u { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut Vec4u { + self.as_mut_vec4() + } +} + +impl Borrow<[u32]> for Vector4u { + #[inline(always)] + fn borrow(&self) -> &[u32] { + >::borrow(self).as_ref() + } +} + +impl BorrowMut<[u32]> for Vector4u { + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [u32] { + >::borrow_mut(self).as_mut() + } +} + +impl ToOwned for Vec4u { + type Owned = Vector4u; + + #[inline(always)] + fn to_owned(&self) -> Self::Owned { + Vector4u { + x: self.x(), + y: self.y(), + z: self.z(), + w: self.w(), + } + } +} + +impl std::fmt::Display for Vector4u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{{}, {}, {}, {}}}", self.x, self.y, self.z, self.w) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_identity() { + let vec = Vector4u::new(4, 2, 0, 0); + + assert_eq!(vec.as_ptr(), &vec[0]); + assert_eq!(vec.as_ptr(), &vec.x); + } + + #[test] + fn test_iter() { + let mut vec = Vector4u::new(4, 2, 1, 0); + + for v in vec.iter_mut() { + *v = *v * 2 + } + + assert_eq!(vec.x, 8); + assert_eq!(vec.y, 4); + assert_eq!(vec.z, 2); + assert_eq!(vec.w, 0); + } +} diff --git a/alloy/src/ops.rs b/alloy/src/ops.rs index 33be9c4..7ff9c81 100644 --- a/alloy/src/ops.rs +++ b/alloy/src/ops.rs @@ -86,7 +86,8 @@ pub trait TryDot { /// /// # Safety /// - /// This function call will be unsafe is `try_dot` does not yield a value. + /// This function call will be undefined-behavior if `try_dot` does not yield + /// a value. unsafe fn dot_unchecked(&self, rhs: &Rhs) -> Self::Output { self.try_dot(rhs).unwrap_unchecked() } @@ -166,3 +167,16 @@ pub trait Cross { /// fn cross(&self, other: &Rhs) -> Self::Output; } + +/// Computes a midpoint of two types. +pub trait Midpoint { + /// The output type + type Output; + + /// Computes the midpoint of this type, returning the result + /// + /// # Arguments + /// + /// * `other` - the other value + fn midpoint(&self, other: &Self) -> Self::Output; +}