diff --git a/src/lib.rs b/src/lib.rs index 727e5c2..ed7a919 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +mod macros; +pub mod vector; #[cfg(test)] mod tests; diff --git a/src/macros/mod.rs b/src/macros/mod.rs new file mode 100644 index 0000000..c7be6b0 --- /dev/null +++ b/src/macros/mod.rs @@ -0,0 +1,241 @@ +// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license) + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_vector { + ( $struct: ident { $($field: ident), + }, ( $($generic: ident), + ), $size: expr ) => { + impl $struct { + /// Constructs a new vector with the specified values for each field. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(0, 0); + /// + /// assert_eq!(vec2.x, 0); + /// assert_eq!(vec2.y, 0); + /// ``` + #[inline(always)] + pub const fn new( $($field: T), + ) -> Self { + Self { + $( $field ), + + } + } + + /// Consumes the vector and returns its values as an array. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(0, 0); + /// let array = vec2.to_array(); + /// + /// assert_eq!(array, [0, 0]); + /// ``` + #[inline(always)] + pub fn to_array(self) -> [T; $size] { + [ $(self.$field), + ] + } + + /// Consumes the vector and returns its values as a tuple. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(0, 0); + /// let tuple = vec2.to_tuple(); + /// + /// assert_eq!(tuple, (0, 0)); + /// ``` + #[inline(always)] + pub fn to_tuple(self) -> ( $($generic), + ) { + ( $(self.$field), + ) + } + + /// Consumes the vector and returns a new vector with the given function applied on each field. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(1, 2) + /// .map(|i| i * 2); + /// + /// assert_eq!(vec2, Vector2::new(2, 4)); + /// ``` + #[inline] + pub fn map(self, f: F) -> $struct + where + F: Fn(T) -> U + { + $struct { + $( $field: f(self.$field) ), + + } + } + } + + impl $struct { + /// Constructs a vector using the given `value` as the value for all of its fields. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::from_value(0); + /// + /// assert_eq!(vec2, Vector2::new(0, 0)); + /// ``` + #[inline(always)] + pub const fn from_value(value: T) -> Self { + Self { + $( $field: value ), + + } + } + } + + impl From<[T; $size]> for $struct { + fn from(from: [T; $size]) -> Self { + let mut iterator = from.into_iter(); + + Self { + // SAFETY: We know the size of `from` so `iterator.next()` is always `Some(..)` + $( $field: unsafe { iterator.next().unwrap_unchecked() } ), + + } + } + } + + impl From<($($generic), +)> for $struct { + fn from(from: ($($generic), +)) -> Self { + let ( $($field), + ) = from; + + Self { + $( $field ), + + } + } + } + + impl core::fmt::Debug for $struct { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let identifier = core::stringify!($struct); + + f.debug_struct(identifier) + $( .field( core::stringify!($field), &self.$field ) ) + + .finish() + } + } + + impl PartialEq for $struct { + fn eq(&self, other: &Self) -> bool { + $( self.$field == other.$field ) && + + } + } + + impl Eq for $struct { } + + impl core::hash::Hash for $struct { + fn hash(&self, state: &mut H) { + $( self.$field.hash(state); ) + + } + } + + impl Clone for $struct { + fn clone(&self) -> Self { + Self { + $( $field: self.$field.clone() ), + + } + } + } + + impl Copy for $struct { } + + impl Default for $struct { + fn default() -> Self { + Self { + $( $field: T::default() ), + + } + } + } + + impl> core::ops::Neg for $struct { + type Output = Self; + + fn neg(self) -> Self::Output { + Self { + $( $field: -self.$field ), + + } + } + } + + // Impl arithmetic pperators + $crate::impl_operator!( $struct { $($field), + }, AddAssign, add_assign ); + $crate::impl_operator!( $struct { $($field), + }, Add, add, Self ); + $crate::impl_operator!( $struct { $($field), + }, SubAssign, sub_assign ); + $crate::impl_operator!( $struct { $($field), + }, Sub, sub, Self ); + $crate::impl_operator!( $struct { $($field), + }, MulAssign, mul_assign ); + $crate::impl_operator!( $struct { $($field), + }, Mul, mul, Self ); + $crate::impl_operator!( $struct { $($field), + }, DivAssign, div_assign ); + $crate::impl_operator!( $struct { $($field), + }, Div, div, Self ); + $crate::impl_operator!( $struct { $($field), + }, RemAssign, rem_assign ); + $crate::impl_operator!( $struct { $($field), + }, Rem, rem, Self ); + + // Impl bitwise operators + $crate::impl_operator!( $struct { $($field), + }, BitAndAssign, bitand_assign ); + $crate::impl_operator!( $struct { $($field), + }, BitAnd, bitand, Self ); + $crate::impl_operator!( $struct { $($field), + }, BitOrAssign, bitor_assign ); + $crate::impl_operator!( $struct { $($field), + }, BitOr, bitor, Self ); + $crate::impl_operator!( $struct { $($field), + }, BitXorAssign, bitxor_assign ); + $crate::impl_operator!( $struct { $($field), + }, BitXor, bitxor, Self ); + + // Impl floating-point based methods + //$crate::impl_floating_point_operations!( $struct { $($field), + }, $size ); + }; +} + + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_operator { + ( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident, $output: ty ) => { + impl> core::ops::$trait for $struct { + type Output = $output; + + fn $method(self, other: Self) -> Self::Output { + Self { + $( $field: self.$field.$method(other.$field) ), + + } + } + } + + impl + Copy> core::ops::$trait for $struct { + type Output = $output; + + fn $method(self, other: T) -> Self::Output { + Self { + $( $field: self.$field.$method(other) ), + + } + } + } + }; + + ( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident ) => { + impl core::ops::$trait for $struct { + fn $method(&mut self, other: Self) { + $( self.$field.$method(other.$field) ); + + } + } + + impl core::ops::$trait for $struct { + fn $method(&mut self, other: T) { + $( self.$field.$method(other) ); + + } + } + }; +} diff --git a/src/vector.rs b/src/vector.rs new file mode 100644 index 0000000..067237f --- /dev/null +++ b/src/vector.rs @@ -0,0 +1,68 @@ +// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license) + +/// Vector for holding two-dimensional values. +/// +/// # Example +/// +/// ``` +/// use fixed_vectors::Vector2; +/// +/// let mut vec2 = Vector2::new(1, 2); +/// vec2 += Vector2::new(1, 2); +/// +/// assert_eq!(vec2.x, 2); +/// assert_eq!(vec2.y, 4); +/// ``` +pub struct Vector2 { + pub x: T, + pub y: T, +} + + +/// Vector for holding three-dimensional values. +/// +/// # Example +/// +/// ``` +/// use fixed_vectors::Vector3; +/// +/// let mut vec3 = Vector3::new(1, 2, 3); +/// vec3 += Vector3::new(1, 2, 3); +/// +/// assert_eq!(vec3.x, 2); +/// assert_eq!(vec3.y, 4); +/// assert_eq!(vec3.z, 6); +/// ``` +pub struct Vector3 { + pub x: T, + pub y: T, + pub z: T, +} + + +/// Vector for holding four-dimensional values. +/// +/// # Example +/// +/// ``` +/// use fixed_vectors::Vector4; +/// +/// let mut vec4 = Vector4::new(1, 2, 3, 4); +/// vec4 += Vector4::new(1, 2, 3, 4); +/// +/// assert_eq!(vec4.x, 2); +/// assert_eq!(vec4.y, 4); +/// assert_eq!(vec4.z, 6); +/// assert_eq!(vec4.w, 8); +/// ``` +pub struct Vector4 { + pub x: T, + pub y: T, + pub z: T, + pub w: T, +} + + +crate::impl_vector!(Vector2 { x, y }, (T, T), 2); +crate::impl_vector!(Vector3 { x, y, z }, (T, T, T), 3); +crate::impl_vector!(Vector4 { x, y, z, w }, (T, T, T, T), 4);