use core::ops::{Add, AddAssign, Index, IndexMut, Mul, Neg, Sub, SubAssign};
use crate::scalar::Numeric;
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq)]
#[must_use]
pub struct Vector<const N: usize, T = f64> {
data: [T; N],
}
impl<const N: usize, T> Vector<N, T> {
#[inline]
pub const fn new(data: [T; N]) -> Self {
Vector { data }
}
#[inline]
pub fn from_fn(f: impl FnMut(usize) -> T) -> Self {
Vector {
data: core::array::from_fn(f),
}
}
#[inline]
#[must_use]
pub const fn as_array(&self) -> &[T; N] {
&self.data
}
#[inline]
#[must_use]
pub const fn as_slice(&self) -> &[T] {
&self.data
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.data
}
#[inline]
#[must_use]
pub fn into_array(self) -> [T; N] {
self.data
}
}
impl<const N: usize, T: Copy> Vector<N, T> {
#[inline]
#[must_use]
pub fn try_from_slice(slice: &[T]) -> Option<Self> {
(slice.len() == N).then(|| Self::from_fn(|i| slice[i]))
}
}
impl<const N: usize, T: Numeric> Vector<N, T> {
#[inline]
pub fn zeros() -> Self {
Vector::from_fn(|_| T::ZERO)
}
#[inline]
pub fn scale(self, scalar: T) -> Self {
Vector::from_fn(|i| self.data[i] * scalar)
}
#[inline]
#[must_use]
pub fn dot(self, rhs: Self) -> T {
let mut sum = T::ZERO;
for (&a, &b) in self.data.iter().zip(&rhs.data) {
sum += a * b;
}
sum
}
#[inline]
#[must_use]
pub fn norm_squared(self) -> T {
self.dot(self)
}
#[inline]
#[must_use]
pub fn norm(self) -> T {
self.norm_squared().sqrt()
}
}
impl<const N: usize, T> From<[T; N]> for Vector<N, T> {
#[inline]
fn from(data: [T; N]) -> Self {
Vector { data }
}
}
impl<const N: usize, T> Index<usize> for Vector<N, T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
&self.data[index]
}
}
impl<const N: usize, T> IndexMut<usize> for Vector<N, T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
&mut self.data[index]
}
}
impl<const N: usize, T: Numeric> Add for Vector<N, T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Vector::from_fn(|i| self.data[i] + rhs.data[i])
}
}
impl<const N: usize, T: Numeric> AddAssign for Vector<N, T> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
for (a, &b) in self.data.iter_mut().zip(&rhs.data) {
*a += b;
}
}
}
impl<const N: usize, T: Numeric> Sub for Vector<N, T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Vector::from_fn(|i| self.data[i] - rhs.data[i])
}
}
impl<const N: usize, T: Numeric> SubAssign for Vector<N, T> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
for (a, &b) in self.data.iter_mut().zip(&rhs.data) {
*a -= b;
}
}
}
impl<const N: usize, T: Numeric> Neg for Vector<N, T> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Vector::from_fn(|i| -self.data[i])
}
}
impl<const N: usize, T: Numeric> Mul<T> for Vector<N, T> {
type Output = Self;
#[inline]
fn mul(self, scalar: T) -> Self {
self.scale(scalar)
}
}
impl<T: Numeric> Vector<3, T> {
#[inline]
pub fn cross(self, rhs: Self) -> Self {
let [ax, ay, az] = self.data;
let [bx, by, bz] = rhs.data;
Vector::new([ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx])
}
#[inline]
#[must_use]
pub fn scalar_triple(self, b: Self, c: Self) -> T {
self.dot(b.cross(c))
}
}
impl<T: Numeric> Vector<2, T> {
#[inline]
#[must_use]
pub fn cross(self, rhs: Self) -> T {
self[0] * rhs[1] - self[1] * rhs[0]
}
}