simple-vectors 0.5.2

Simple, dimension generic vector math
Documentation
#![deny(missing_docs)]

/*!
A simple, dimension-generic vector math library.

This crate provides a generic `Vector` type for performing vector operations with compile-time dimension checking. It's designed to be lightweight, and integrates well with the `vector-space` ecosystem.

# Features

- **Dimension and type generic**: Works with vectors of any compile-time dimension and scalar type
- **Trait integration**: Implements `VectorSpace`, `DotProduct`, and `InnerSpace`
- **Optional parsing**: Parsing support via the `parsable` feature

# Basic Usage

```rust
use scalars::Zero;
use simple_vectors::Vector;

// Create a 3D vector
let v = Vector::new([1.0, 2.0, 3.0]);
let w = Vector::new([4.0, 5.0, 6.0]);

// Basic arithmetic
let sum = v + w;
let scaled = v * 2.0;

// Dot product
let dot = v * w;

// Zero vector
let zero = Vector::<f64, 3>::zero();
```

# Examples

## 2D Vector Operations

```rust
use simple_vectors::Vector;

let position = Vector::new([10.0, 20.0]);
let velocity = Vector::new([5.0, -2.0]);
let new_position = position + velocity;
```

## Generic Dimension Functions

```rust
use scalars::Real;
use simple_vectors::Vector;

fn magnitude<T: Real, const N: usize>(v: Vector<T, N>) -> T {
    (v * v).sqrt()
}

let v = Vector::new([1.0, 2.0, 3.0]);
let mag = magnitude(v);
```

# Integration with vector-space

This crate implements the standard `vector-space` traits, making it compatible
with other libraries in the ecosystem:

```rust
use simple_vectors::Vector;
use inner_space::{InnerSpace, distance};

let v = Vector::new([1.0, 2.0]);
let w = Vector::new([3.0, 4.0]);

// Both work the same:
let dis1 = distance(v, w);
let dis2 = (w - v).magnitude();

assert_eq!(dis1, dis2);
```
*/

use inner_space::{DotProduct, VectorSpace};
use scalars::{Real, Zero};
use vector_basis::Basis;

use std::{
    iter::Sum,
    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
};

/// A generic, fixed-size vector with compile-time dimension checking.
///
/// The `Vector` type represents a mathematical vector with `N` components
/// of type `T`. It provides common vector operations and integrates with
/// the `vector-space` trait ecosystem.
///
/// # Type Parameters
///
/// - `T`: The scalar type of vector components (must implement relevant traits for operations)
/// - `N`: The dimension of the vector (must be a compile-time constant)
///
/// # Examples
///
/// Basic usage with f32:
///
/// ```
/// use simple_vectors::Vector;
///
/// let v = Vector::new([1.0, 2.0, 3.0]);
/// assert_eq!(v[0], 1.0);
/// assert_eq!(v[1], 2.0);
/// assert_eq!(v[2], 3.0);
/// ```
///
/// Using with integer types:
///
/// ```
/// use simple_vectors::Vector;
///
/// let int_vec = Vector::new([1, 2, 3, 4]);
/// let scaled = int_vec * 2;
/// assert_eq!(scaled, Vector::new([2, 4, 6, 8]));
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Vector<T, const N: usize>([T; N]);

impl<T, const N: usize> Vector<T, N> {
    /// Creates a new vector from the given array of elements.
    ///
    /// This is a const function, allowing vector creation in const contexts.
    ///
    /// # Arguments
    ///
    /// * `elements` - An array of `N` elements to initialize the vector
    ///
    /// # Examples
    ///
    /// ```
    /// use simple_vectors::Vector;
    ///
    /// const V: Vector<i32, 3> = Vector::new([1, 2, 3]);
    /// assert_eq!(V, Vector::new([1, 2, 3]));
    /// ```
    ///
    /// Creating a 2D vector:
    /// ```
    /// use simple_vectors::Vector;
    ///
    /// let point = Vector::new([10.5, 20.3]);
    /// ```
    pub const fn new(elements: [T; N]) -> Self {
        Self(elements)
    }
}

impl<T: Real, const N: usize, const I: usize> Basis<I> for Vector<T, N> {
    fn unit_basis() -> Self {
        let mut result = Self::zero();
        result.0[I] = T::one();
        result
    }

    fn basis_of(magnitude: T) -> Self {
        let mut result = Self::zero();
        result.0[I] = magnitude;
        result
    }

    fn basis(&self) -> Self::Scalar {
        self.0[I]
    }

    fn basis_mut(&mut self) -> &mut Self::Scalar {
        &mut self.0[I]
    }
}

impl<T: Default + Copy, const N: usize> Default for Vector<T, N> {
    fn default() -> Self {
        Self([T::default(); N])
    }
}

impl<T, const N: usize> Add<Self> for Vector<T, N>
where
    T: Add<Output = T> + Copy,
{
    type Output = Self;
    fn add(mut self, other: Self) -> Self {
        for (element, &other_element) in self.0.iter_mut().zip(other.0.iter()) {
            *element = *element + other_element;
        }
        self
    }
}

impl<T, const N: usize> AddAssign<Self> for Vector<T, N>
where
    T: AddAssign + Copy,
{
    fn add_assign(&mut self, other: Self) {
        for (element, &other_element) in self.0.iter_mut().zip(other.0.iter()) {
            *element += other_element;
        }
    }
}

impl<T, const N: usize> Sub<Self> for Vector<T, N>
where
    T: Sub<Output = T> + Copy,
{
    type Output = Self;
    fn sub(mut self, other: Self) -> Self {
        for (element, &other_element) in self.0.iter_mut().zip(other.0.iter()) {
            *element = *element - other_element;
        }
        self
    }
}

impl<T, const N: usize> SubAssign<Self> for Vector<T, N>
where
    T: SubAssign + Copy,
{
    fn sub_assign(&mut self, other: Self) {
        for (element, &other_element) in self.0.iter_mut().zip(other.0.iter()) {
            *element -= other_element;
        }
    }
}

impl<T, const N: usize> Neg for Vector<T, N>
where
    T: Neg<Output = T> + Copy,
{
    type Output = Self;
    fn neg(mut self) -> Self {
        for element in &mut self.0 {
            *element = -*element;
        }
        self
    }
}

impl<T, const N: usize> Mul<T> for Vector<T, N>
where
    T: Mul<Output = T> + Copy,
{
    type Output = Self;
    fn mul(mut self, other: T) -> Self {
        for element in &mut self.0 {
            *element = *element * other;
        }
        self
    }
}

impl<T, const N: usize> MulAssign<T> for Vector<T, N>
where
    T: MulAssign + Copy,
{
    fn mul_assign(&mut self, other: T) {
        for element in &mut self.0 {
            *element *= other;
        }
    }
}

impl<T, const N: usize> Div<T> for Vector<T, N>
where
    T: Div<Output = T> + Copy,
{
    type Output = Self;
    fn div(mut self, other: T) -> Self {
        for element in &mut self.0 {
            *element = *element / other;
        }
        self
    }
}

impl<T, const N: usize> DivAssign<T> for Vector<T, N>
where
    T: DivAssign + Copy,
{
    fn div_assign(&mut self, other: T) {
        for element in &mut self.0 {
            *element /= other;
        }
    }
}

impl<T, const N: usize> Mul<Self> for Vector<T, N>
where
    T: Add<Output = T> + Mul<Output = T> + Zero + Copy,
{
    type Output = T;
    fn mul(self, other: Self) -> T {
        self.0
            .iter()
            .zip(other.0.iter())
            .fold(T::zero(), |result, (&left, &right)| result + left * right)
    }
}

impl<T: Zero + Copy, const N: usize> Zero for Vector<T, N> {
    fn zero() -> Self {
        Self([T::zero(); N])
    }

    fn is_zero(&self) -> bool {
        self.0.iter().all(Zero::is_zero)
    }
}

impl<T: Real, const N: usize> VectorSpace for Vector<T, N> {
    type Scalar = T;
}

impl<T: Real, const N: usize> DotProduct for Vector<T, N> {
    type Output = Self::Scalar;
    fn dot(&self, other: &Self) -> T {
        *self * *other
    }
}

impl<T, const N: usize> From<[T; N]> for Vector<T, N> {
    fn from(elements: [T; N]) -> Self {
        Self::new(elements)
    }
}

impl<T, const N: usize> From<Vector<T, N>> for [T; N] {
    fn from(val: Vector<T, N>) -> Self {
        val.0
    }
}

impl<'a, T, const N: usize> From<&'a Vector<T, N>> for &'a [T; N] {
    fn from(val: &'a Vector<T, N>) -> Self {
        &val.0
    }
}

impl<'a, T, const N: usize> From<&'a mut Vector<T, N>> for &'a mut [T; N] {
    fn from(val: &'a mut Vector<T, N>) -> Self {
        &mut val.0
    }
}

impl<'a, T, const N: usize> From<&'a Vector<T, N>> for &'a [T] {
    fn from(val: &'a Vector<T, N>) -> Self {
        &val.0
    }
}

impl<'a, T, const N: usize> From<&'a mut Vector<T, N>> for &'a mut [T] {
    fn from(val: &'a mut Vector<T, N>) -> Self {
        &mut val.0
    }
}

impl<I, T, const N: usize> Index<I> for Vector<T, N>
where
    [T; N]: Index<I>,
{
    type Output = <[T; N] as Index<I>>::Output;
    fn index(&self, index: I) -> &Self::Output {
        &self.0[index]
    }
}

impl<I, T, const N: usize> IndexMut<I> for Vector<T, N>
where
    [T; N]: IndexMut<I>,
{
    fn index_mut(&mut self, index: I) -> &mut Self::Output {
        &mut self.0[index]
    }
}

impl<T, const N: usize> Sum for Vector<T, N>
where
    T: Add<Output = T> + Zero + Copy,
{
    fn sum<I>(iter: I) -> Self
    where
        I: Iterator<Item = Self>,
    {
        iter.fold(Self::zero(), |acc, v| acc + v)
    }
}

mod point;

pub use point::Point;

#[cfg(feature = "parsable")]
mod parsable;