simple_vectors/
lib.rs

1#![deny(missing_docs)]
2
3/*!
4A simple, dimension-generic vector math library.
5
6This 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.
7
8# Features
9
10- **Dimension and type generic**: Works with vectors of any compile-time dimension and scalar type
11- **Trait integration**: Implements `VectorSpace`, `DotProduct`, and `InnerSpace`
12- **Optional parsing**: Parsing support via the `parsable` feature
13
14# Basic Usage
15
16```rust
17use num_traits::Zero;
18use simple_vectors::Vector;
19
20// Create a 3D vector
21let v = Vector::new([1.0, 2.0, 3.0]);
22let w = Vector::new([4.0, 5.0, 6.0]);
23
24// Basic arithmetic
25let sum = v + w;
26let scaled = v * 2.0;
27
28// Dot product
29let dot = v * w;
30
31// Zero vector
32let zero = Vector::<f64, 3>::zero();
33```
34
35# Examples
36
37## 2D Vector Operations
38
39```rust
40use simple_vectors::Vector;
41
42let position = Vector::new([10.0, 20.0]);
43let velocity = Vector::new([5.0, -2.0]);
44let new_position = position + velocity;
45```
46
47## Generic Dimension Functions
48
49```rust
50use num_traits::real::Real;
51use simple_vectors::Vector;
52
53fn magnitude<T: Real, const N: usize>(v: Vector<T, N>) -> T {
54    (v * v).sqrt()
55}
56
57let v = Vector::new([1.0, 2.0, 3.0]);
58let mag = magnitude(v);
59```
60
61# Integration with vector-space
62
63This crate implements the standard `vector-space` traits, making it compatible
64with other libraries in the ecosystem:
65
66```rust
67use simple_vectors::Vector;
68use vector_space::{InnerSpace, distance};
69
70let v = Vector::new([1.0, 2.0]);
71let w = Vector::new([3.0, 4.0]);
72
73// Both work the same:
74let dis1 = distance(v, w);
75let dis2 = (w - v).magnitude();
76
77assert_eq!(dis1, dis2);
78```
79*/
80
81use num_traits::{Zero, real::Real};
82use vector_basis::Basis;
83use vector_space::{DotProduct, InnerSpace, VectorSpace};
84
85use std::ops::{
86    Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
87};
88
89/// A generic, fixed-size vector with compile-time dimension checking.
90///
91/// The `Vector` type represents a mathematical vector with `N` components
92/// of type `T`. It provides common vector operations and integrates with
93/// the `vector-space` trait ecosystem.
94///
95/// # Type Parameters
96///
97/// - `T`: The scalar type of vector components (must implement relevant traits for operations)
98/// - `N`: The dimension of the vector (must be a compile-time constant)
99///
100/// # Examples
101///
102/// Basic usage with f32:
103///
104/// ```
105/// use simple_vectors::Vector;
106///
107/// let v = Vector::new([1.0, 2.0, 3.0]);
108/// assert_eq!(v[0], 1.0);
109/// assert_eq!(v[1], 2.0);
110/// assert_eq!(v[2], 3.0);
111/// ```
112///
113/// Using with integer types:
114///
115/// ```
116/// use simple_vectors::Vector;
117///
118/// let int_vec = Vector::new([1, 2, 3, 4]);
119/// let scaled = int_vec * 2;
120/// assert_eq!(scaled, Vector::new([2, 4, 6, 8]));
121/// ```
122#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
123pub struct Vector<T, const N: usize>([T; N]);
124
125impl<T, const N: usize> Vector<T, N> {
126    /// Creates a new vector from the given array of elements.
127    ///
128    /// This is a const function, allowing vector creation in const contexts.
129    ///
130    /// # Arguments
131    ///
132    /// * `elements` - An array of `N` elements to initialize the vector
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// use simple_vectors::Vector;
138    ///
139    /// const V: Vector<i32, 3> = Vector::new([1, 2, 3]);
140    /// assert_eq!(V, Vector::new([1, 2, 3]));
141    /// ```
142    ///
143    /// Creating a 2D vector:
144    /// ```
145    /// use simple_vectors::Vector;
146    ///
147    /// let point = Vector::new([10.5, 20.3]);
148    /// ```
149    pub const fn new(elements: [T; N]) -> Self {
150        Self(elements)
151    }
152}
153
154impl<T: Real, const N: usize, const I: usize> Basis<I> for Vector<T, N> {
155    fn unit_basis() -> Self {
156        let mut result = Self::zero();
157        result.0[I] = T::one();
158        result
159    }
160
161    fn basis_of(magnitude: T) -> Self {
162        let mut result = Self::zero();
163        result.0[I] = magnitude;
164        result
165    }
166
167    fn basis(&self) -> Self::Scalar {
168        self.0[I]
169    }
170
171    fn basis_mut(&mut self) -> &mut Self::Scalar {
172        &mut self.0[I]
173    }
174}
175
176impl<T: Default + Copy, const N: usize> Default for Vector<T, N> {
177    fn default() -> Self {
178        Self([T::default(); N])
179    }
180}
181
182impl<T, const N: usize> Add<Self> for Vector<T, N>
183where
184    T: Add<Output = T> + Copy,
185{
186    type Output = Self;
187    fn add(mut self, other: Self) -> Self {
188        for i in 0..N {
189            self.0[i] = self.0[i] + other.0[i];
190        }
191        self
192    }
193}
194
195impl<T, const N: usize> AddAssign<Self> for Vector<T, N>
196where
197    T: AddAssign + Copy,
198{
199    fn add_assign(&mut self, other: Self) {
200        for i in 0..N {
201            self.0[i] += other.0[i];
202        }
203    }
204}
205
206impl<T, const N: usize> Sub<Self> for Vector<T, N>
207where
208    T: Sub<Output = T> + Copy,
209{
210    type Output = Self;
211    fn sub(mut self, other: Self) -> Self {
212        for i in 0..N {
213            self.0[i] = self.0[i] - other.0[i];
214        }
215        self
216    }
217}
218
219impl<T, const N: usize> SubAssign<Self> for Vector<T, N>
220where
221    T: SubAssign + Copy,
222{
223    fn sub_assign(&mut self, other: Self) {
224        for i in 0..N {
225            self.0[i] -= other.0[i];
226        }
227    }
228}
229
230impl<T, const N: usize> Neg for Vector<T, N>
231where
232    T: Neg<Output = T> + Copy,
233{
234    type Output = Self;
235    fn neg(mut self) -> Self {
236        for i in 0..N {
237            self.0[i] = -self.0[i];
238        }
239        self
240    }
241}
242
243impl<T, const N: usize> Mul<T> for Vector<T, N>
244where
245    T: Mul<Output = T> + Copy,
246{
247    type Output = Self;
248    fn mul(mut self, other: T) -> Self {
249        for i in 0..N {
250            self.0[i] = self.0[i] * other;
251        }
252        self
253    }
254}
255
256impl<T, const N: usize> MulAssign<T> for Vector<T, N>
257where
258    T: MulAssign + Copy,
259{
260    fn mul_assign(&mut self, other: T) {
261        for i in 0..N {
262            self.0[i] *= other;
263        }
264    }
265}
266
267impl<T, const N: usize> Div<T> for Vector<T, N>
268where
269    T: Div<Output = T> + Copy,
270{
271    type Output = Self;
272    fn div(mut self, other: T) -> Self {
273        for i in 0..N {
274            self.0[i] = self.0[i] / other;
275        }
276        self
277    }
278}
279
280impl<T, const N: usize> DivAssign<T> for Vector<T, N>
281where
282    T: DivAssign + Copy,
283{
284    fn div_assign(&mut self, other: T) {
285        for i in 0..N {
286            self.0[i] /= other;
287        }
288    }
289}
290
291impl<T, const N: usize> Mul<Self> for Vector<T, N>
292where
293    T: Add<Output = T> + Mul<Output = T> + Zero + Copy,
294{
295    type Output = T;
296    fn mul(self, other: Self) -> T {
297        self.0
298            .iter()
299            .zip(other.0.iter())
300            .fold(T::zero(), |result, (&left, &right)| result + left * right)
301    }
302}
303
304impl<T: Zero + Copy, const N: usize> Zero for Vector<T, N> {
305    fn zero() -> Self {
306        Self([T::zero(); N])
307    }
308
309    fn is_zero(&self) -> bool {
310        for i in 0..N {
311            if !self.0[i].is_zero() {
312                return false;
313            }
314        }
315        true
316    }
317}
318
319impl<T: Real, const N: usize> VectorSpace for Vector<T, N> {
320    type Scalar = T;
321}
322
323impl<T: Real, const N: usize> DotProduct for Vector<T, N> {
324    type Output = Self::Scalar;
325    fn dot(self, other: Self) -> T {
326        self * other
327    }
328}
329
330impl<T: Real, const N: usize> InnerSpace for Vector<T, N> {
331    fn scalar(self, other: Self) -> T {
332        self * other
333    }
334}
335
336impl<T, const N: usize> From<[T; N]> for Vector<T, N> {
337    fn from(elements: [T; N]) -> Self {
338        Self::new(elements)
339    }
340}
341
342impl<T, const N: usize> From<Vector<T, N>> for [T; N] {
343    fn from(val: Vector<T, N>) -> Self {
344        val.0
345    }
346}
347
348impl<'a, T, const N: usize> From<&'a Vector<T, N>> for &'a [T; N] {
349    fn from(val: &'a Vector<T, N>) -> Self {
350        &val.0
351    }
352}
353
354impl<'a, T, const N: usize> From<&'a mut Vector<T, N>> for &'a mut [T; N] {
355    fn from(val: &'a mut Vector<T, N>) -> Self {
356        &mut val.0
357    }
358}
359
360// Optional but very useful: slice conversions
361impl<'a, T, const N: usize> From<&'a Vector<T, N>> for &'a [T] {
362    fn from(val: &'a Vector<T, N>) -> Self {
363        &val.0
364    }
365}
366
367impl<'a, T, const N: usize> From<&'a mut Vector<T, N>> for &'a mut [T] {
368    fn from(val: &'a mut Vector<T, N>) -> Self {
369        &mut val.0
370    }
371}
372
373impl<I, T, const N: usize> Index<I> for Vector<T, N>
374where
375    [T; N]: Index<I>,
376{
377    type Output = <[T; N] as Index<I>>::Output;
378    fn index(&self, index: I) -> &Self::Output {
379        &self.0[index]
380    }
381}
382
383impl<I, T, const N: usize> IndexMut<I> for Vector<T, N>
384where
385    [T; N]: IndexMut<I>,
386{
387    fn index_mut(&mut self, index: I) -> &mut Self::Output {
388        &mut self.0[index]
389    }
390}
391
392#[cfg(feature = "parsable")]
393mod parsable;