Skip to main content

use_vector/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4//! Small vector primitives and operations for `RustUse`.
5
6#[doc(inline)]
7pub use vector2::Vector2;
8#[doc(inline)]
9pub use vector3::Vector3;
10#[doc(inline)]
11pub use vector4::Vector4;
12
13/// Two-dimensional vector primitives and operations.
14pub mod vector2 {
15    use core::ops::{Add, Div, Mul, Neg, Sub};
16
17    #[inline]
18    fn dot2(a0: f64, b0: f64, a1: f64, b1: f64) -> f64 {
19        a0.mul_add(b0, a1 * b1)
20    }
21
22    /// A two-dimensional vector.
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use use_vector::Vector2;
28    ///
29    /// let vector = Vector2::new(3.0, 4.0);
30    ///
31    /// assert_eq!(vector.magnitude(), 5.0);
32    /// ```
33    #[derive(Debug, Clone, Copy, PartialEq)]
34    pub struct Vector2 {
35        /// The x component.
36        pub x: f64,
37        /// The y component.
38        pub y: f64,
39    }
40
41    impl Vector2 {
42        /// The zero vector.
43        pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
44
45        /// A vector with every component set to `1.0`.
46        pub const ONE: Self = Self { x: 1.0, y: 1.0 };
47
48        /// Creates a vector from its components.
49        #[must_use]
50        pub const fn new(x: f64, y: f64) -> Self {
51            Self { x, y }
52        }
53
54        /// Returns the dot product with `other`.
55        ///
56        /// # Examples
57        ///
58        /// ```
59        /// use use_vector::Vector2;
60        ///
61        /// let a = Vector2::new(1.0, 2.0);
62        /// let b = Vector2::new(3.0, 4.0);
63        ///
64        /// assert_eq!(a.dot(b), 11.0);
65        /// ```
66        #[must_use]
67        pub fn dot(self, other: Self) -> f64 {
68            dot2(self.x, other.x, self.y, other.y)
69        }
70
71        /// Returns the squared Euclidean magnitude.
72        #[must_use]
73        pub fn magnitude_squared(self) -> f64 {
74            self.dot(self)
75        }
76
77        /// Returns the Euclidean magnitude.
78        #[must_use]
79        pub fn magnitude(self) -> f64 {
80            self.magnitude_squared().sqrt()
81        }
82
83        /// Returns a normalized vector when the magnitude is finite and non-zero.
84        ///
85        /// Returns `None` for zero vectors or vectors with non-finite magnitude.
86        ///
87        /// # Examples
88        ///
89        /// ```
90        /// use use_vector::Vector2;
91        ///
92        /// let unit = Vector2::new(3.0, 4.0)
93        ///     .normalize()
94        ///     .expect("non-zero finite vector should normalize");
95        ///
96        /// assert!((unit.x - 0.6).abs() < 1.0e-12);
97        /// assert!((unit.y - 0.8).abs() < 1.0e-12);
98        /// ```
99        #[must_use]
100        pub fn normalize(self) -> Option<Self> {
101            let magnitude = self.magnitude();
102
103            if magnitude == 0.0 || !magnitude.is_finite() {
104                return None;
105            }
106
107            Some(self / magnitude)
108        }
109
110        /// Returns the vector scaled by `scalar`.
111        #[must_use]
112        pub fn scale(self, scalar: f64) -> Self {
113            self * scalar
114        }
115
116        /// Returns the Euclidean distance to `other`.
117        ///
118        /// # Examples
119        ///
120        /// ```
121        /// use use_vector::Vector2;
122        ///
123        /// let start = Vector2::ZERO;
124        /// let end = Vector2::new(3.0, 4.0);
125        ///
126        /// assert_eq!(start.distance(end), 5.0);
127        /// ```
128        #[must_use]
129        pub fn distance(self, other: Self) -> f64 {
130            (other - self).magnitude()
131        }
132
133        /// Returns the squared Euclidean distance to `other`.
134        #[must_use]
135        pub fn distance_squared(self, other: Self) -> f64 {
136            (other - self).magnitude_squared()
137        }
138
139        /// Returns the linear interpolation between `self` and `other` for `t`.
140        #[must_use]
141        pub fn lerp(self, other: Self, t: f64) -> Self {
142            self + (other - self) * t
143        }
144    }
145
146    impl Add for Vector2 {
147        type Output = Self;
148
149        fn add(self, rhs: Self) -> Self::Output {
150            Self::new(self.x + rhs.x, self.y + rhs.y)
151        }
152    }
153
154    impl Sub for Vector2 {
155        type Output = Self;
156
157        fn sub(self, rhs: Self) -> Self::Output {
158            Self::new(self.x - rhs.x, self.y - rhs.y)
159        }
160    }
161
162    impl Mul<f64> for Vector2 {
163        type Output = Self;
164
165        fn mul(self, rhs: f64) -> Self::Output {
166            Self::new(self.x * rhs, self.y * rhs)
167        }
168    }
169
170    impl Div<f64> for Vector2 {
171        type Output = Self;
172
173        fn div(self, rhs: f64) -> Self::Output {
174            Self::new(self.x / rhs, self.y / rhs)
175        }
176    }
177
178    impl Neg for Vector2 {
179        type Output = Self;
180
181        fn neg(self) -> Self::Output {
182            Self::new(-self.x, -self.y)
183        }
184    }
185}
186
187/// Three-dimensional vector primitives and operations.
188pub mod vector3 {
189    use core::ops::{Add, Div, Mul, Neg, Sub};
190
191    #[inline]
192    fn dot3(a0: f64, b0: f64, a1: f64, b1: f64, a2: f64, b2: f64) -> f64 {
193        a0.mul_add(b0, a1.mul_add(b1, a2 * b2))
194    }
195
196    #[inline]
197    fn mul_sub(a: f64, b: f64, c: f64, d: f64) -> f64 {
198        a.mul_add(b, -(c * d))
199    }
200
201    /// A three-dimensional vector.
202    ///
203    /// # Examples
204    ///
205    /// ```
206    /// use use_vector::Vector3;
207    ///
208    /// let vector = Vector3::new(2.0, 3.0, 6.0);
209    ///
210    /// assert_eq!(vector.magnitude(), 7.0);
211    /// ```
212    #[derive(Debug, Clone, Copy, PartialEq)]
213    pub struct Vector3 {
214        /// The x component.
215        pub x: f64,
216        /// The y component.
217        pub y: f64,
218        /// The z component.
219        pub z: f64,
220    }
221
222    impl Vector3 {
223        /// The zero vector.
224        pub const ZERO: Self = Self {
225            x: 0.0,
226            y: 0.0,
227            z: 0.0,
228        };
229
230        /// A vector with every component set to `1.0`.
231        pub const ONE: Self = Self {
232            x: 1.0,
233            y: 1.0,
234            z: 1.0,
235        };
236
237        /// Creates a vector from its components.
238        #[must_use]
239        pub const fn new(x: f64, y: f64, z: f64) -> Self {
240            Self { x, y, z }
241        }
242
243        /// Returns the dot product with `other`.
244        #[must_use]
245        pub fn dot(self, other: Self) -> f64 {
246            dot3(self.x, other.x, self.y, other.y, self.z, other.z)
247        }
248
249        /// Returns the squared Euclidean magnitude.
250        #[must_use]
251        pub fn magnitude_squared(self) -> f64 {
252            self.dot(self)
253        }
254
255        /// Returns the Euclidean magnitude.
256        #[must_use]
257        pub fn magnitude(self) -> f64 {
258            self.magnitude_squared().sqrt()
259        }
260
261        /// Returns a normalized vector when the magnitude is finite and non-zero.
262        ///
263        /// Returns `None` for zero vectors or vectors with non-finite magnitude.
264        #[must_use]
265        pub fn normalize(self) -> Option<Self> {
266            let magnitude = self.magnitude();
267
268            if magnitude == 0.0 || !magnitude.is_finite() {
269                return None;
270            }
271
272            Some(self / magnitude)
273        }
274
275        /// Returns the vector scaled by `scalar`.
276        #[must_use]
277        pub fn scale(self, scalar: f64) -> Self {
278            self * scalar
279        }
280
281        /// Returns the Euclidean distance to `other`.
282        #[must_use]
283        pub fn distance(self, other: Self) -> f64 {
284            (other - self).magnitude()
285        }
286
287        /// Returns the squared Euclidean distance to `other`.
288        #[must_use]
289        pub fn distance_squared(self, other: Self) -> f64 {
290            (other - self).magnitude_squared()
291        }
292
293        /// Returns the linear interpolation between `self` and `other` for `t`.
294        #[must_use]
295        pub fn lerp(self, other: Self, t: f64) -> Self {
296            self + (other - self) * t
297        }
298
299        /// Returns the cross product with `other`.
300        ///
301        /// # Examples
302        ///
303        /// ```
304        /// use use_vector::Vector3;
305        ///
306        /// let x = Vector3::new(1.0, 0.0, 0.0);
307        /// let y = Vector3::new(0.0, 1.0, 0.0);
308        ///
309        /// assert_eq!(x.cross(y), Vector3::new(0.0, 0.0, 1.0));
310        /// ```
311        #[must_use]
312        pub fn cross(self, other: Self) -> Self {
313            Self::new(
314                mul_sub(self.y, other.z, self.z, other.y),
315                mul_sub(self.z, other.x, self.x, other.z),
316                mul_sub(self.x, other.y, self.y, other.x),
317            )
318        }
319    }
320
321    impl Add for Vector3 {
322        type Output = Self;
323
324        fn add(self, rhs: Self) -> Self::Output {
325            Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
326        }
327    }
328
329    impl Sub for Vector3 {
330        type Output = Self;
331
332        fn sub(self, rhs: Self) -> Self::Output {
333            Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
334        }
335    }
336
337    impl Mul<f64> for Vector3 {
338        type Output = Self;
339
340        fn mul(self, rhs: f64) -> Self::Output {
341            Self::new(self.x * rhs, self.y * rhs, self.z * rhs)
342        }
343    }
344
345    impl Div<f64> for Vector3 {
346        type Output = Self;
347
348        fn div(self, rhs: f64) -> Self::Output {
349            Self::new(self.x / rhs, self.y / rhs, self.z / rhs)
350        }
351    }
352
353    impl Neg for Vector3 {
354        type Output = Self;
355
356        fn neg(self) -> Self::Output {
357            Self::new(-self.x, -self.y, -self.z)
358        }
359    }
360}
361
362/// Four-dimensional vector primitives and operations.
363pub mod vector4 {
364    use core::ops::{Add, Div, Mul, Neg, Sub};
365
366    #[inline]
367    fn dot4(a0: f64, b0: f64, a1: f64, b1: f64, a2: f64, b2: f64, a3: f64, b3: f64) -> f64 {
368        a0.mul_add(b0, a1.mul_add(b1, a2.mul_add(b2, a3 * b3)))
369    }
370
371    /// A four-dimensional vector.
372    #[derive(Debug, Clone, Copy, PartialEq)]
373    pub struct Vector4 {
374        /// The x component.
375        pub x: f64,
376        /// The y component.
377        pub y: f64,
378        /// The z component.
379        pub z: f64,
380        /// The w component.
381        pub w: f64,
382    }
383
384    impl Vector4 {
385        /// The zero vector.
386        pub const ZERO: Self = Self {
387            x: 0.0,
388            y: 0.0,
389            z: 0.0,
390            w: 0.0,
391        };
392
393        /// A vector with every component set to `1.0`.
394        pub const ONE: Self = Self {
395            x: 1.0,
396            y: 1.0,
397            z: 1.0,
398            w: 1.0,
399        };
400
401        /// Creates a vector from its components.
402        #[must_use]
403        pub const fn new(x: f64, y: f64, z: f64, w: f64) -> Self {
404            Self { x, y, z, w }
405        }
406
407        /// Returns the dot product with `other`.
408        #[must_use]
409        pub fn dot(self, other: Self) -> f64 {
410            dot4(
411                self.x, other.x, self.y, other.y, self.z, other.z, self.w, other.w,
412            )
413        }
414
415        /// Returns the squared Euclidean magnitude.
416        #[must_use]
417        pub fn magnitude_squared(self) -> f64 {
418            self.dot(self)
419        }
420
421        /// Returns the Euclidean magnitude.
422        #[must_use]
423        pub fn magnitude(self) -> f64 {
424            self.magnitude_squared().sqrt()
425        }
426
427        /// Returns a normalized vector when the magnitude is finite and non-zero.
428        ///
429        /// Returns `None` for zero vectors or vectors with non-finite magnitude.
430        #[must_use]
431        pub fn normalize(self) -> Option<Self> {
432            let magnitude = self.magnitude();
433
434            if magnitude == 0.0 || !magnitude.is_finite() {
435                return None;
436            }
437
438            Some(self / magnitude)
439        }
440
441        /// Returns the vector scaled by `scalar`.
442        #[must_use]
443        pub fn scale(self, scalar: f64) -> Self {
444            self * scalar
445        }
446
447        /// Returns the Euclidean distance to `other`.
448        #[must_use]
449        pub fn distance(self, other: Self) -> f64 {
450            (other - self).magnitude()
451        }
452
453        /// Returns the squared Euclidean distance to `other`.
454        #[must_use]
455        pub fn distance_squared(self, other: Self) -> f64 {
456            (other - self).magnitude_squared()
457        }
458
459        /// Returns the linear interpolation between `self` and `other` for `t`.
460        #[must_use]
461        pub fn lerp(self, other: Self, t: f64) -> Self {
462            self + (other - self) * t
463        }
464    }
465
466    impl Add for Vector4 {
467        type Output = Self;
468
469        fn add(self, rhs: Self) -> Self::Output {
470            Self::new(
471                self.x + rhs.x,
472                self.y + rhs.y,
473                self.z + rhs.z,
474                self.w + rhs.w,
475            )
476        }
477    }
478
479    impl Sub for Vector4 {
480        type Output = Self;
481
482        fn sub(self, rhs: Self) -> Self::Output {
483            Self::new(
484                self.x - rhs.x,
485                self.y - rhs.y,
486                self.z - rhs.z,
487                self.w - rhs.w,
488            )
489        }
490    }
491
492    impl Mul<f64> for Vector4 {
493        type Output = Self;
494
495        fn mul(self, rhs: f64) -> Self::Output {
496            Self::new(self.x * rhs, self.y * rhs, self.z * rhs, self.w * rhs)
497        }
498    }
499
500    impl Div<f64> for Vector4 {
501        type Output = Self;
502
503        fn div(self, rhs: f64) -> Self::Output {
504            Self::new(self.x / rhs, self.y / rhs, self.z / rhs, self.w / rhs)
505        }
506    }
507
508    impl Neg for Vector4 {
509        type Output = Self;
510
511        fn neg(self) -> Self::Output {
512            Self::new(-self.x, -self.y, -self.z, -self.w)
513        }
514    }
515}
516
517#[cfg(test)]
518mod tests {
519    use super::{Vector2, Vector3, Vector4};
520
521    fn approx_eq(left: f64, right: f64) -> bool {
522        (left - right).abs() < 1.0e-12
523    }
524
525    fn assert_vector2_close(actual: Vector2, expected: Vector2) {
526        assert!(
527            approx_eq(actual.x, expected.x) && approx_eq(actual.y, expected.y),
528            "expected {expected:?}, got {actual:?}"
529        );
530    }
531
532    fn assert_vector3_close(actual: Vector3, expected: Vector3) {
533        assert!(
534            approx_eq(actual.x, expected.x)
535                && approx_eq(actual.y, expected.y)
536                && approx_eq(actual.z, expected.z),
537            "expected {expected:?}, got {actual:?}"
538        );
539    }
540
541    fn assert_vector4_close(actual: Vector4, expected: Vector4) {
542        assert!(
543            approx_eq(actual.x, expected.x)
544                && approx_eq(actual.y, expected.y)
545                && approx_eq(actual.z, expected.z)
546                && approx_eq(actual.w, expected.w),
547            "expected {expected:?}, got {actual:?}"
548        );
549    }
550
551    #[test]
552    fn vector2_supports_core_operations() {
553        let constructed = Vector2::new(3.0, 4.0);
554
555        assert_vector2_close(constructed, Vector2 { x: 3.0, y: 4.0 });
556        assert_vector2_close(Vector2::ZERO, Vector2::new(0.0, 0.0));
557        assert_vector2_close(Vector2::ONE, Vector2::new(1.0, 1.0));
558        assert_vector2_close(constructed + Vector2::ONE, Vector2::new(4.0, 5.0));
559        assert_vector2_close(constructed - Vector2::ONE, Vector2::new(2.0, 3.0));
560        assert_vector2_close(constructed * 2.0, Vector2::new(6.0, 8.0));
561        assert_vector2_close(constructed / 2.0, Vector2::new(1.5, 2.0));
562        assert_vector2_close(-constructed, Vector2::new(-3.0, -4.0));
563        assert!(approx_eq(constructed.dot(Vector2::new(-2.0, 1.0)), -2.0));
564        assert!(approx_eq(constructed.magnitude_squared(), 25.0));
565        assert!(approx_eq(constructed.magnitude(), 5.0));
566        assert_vector2_close(constructed.scale(0.5), Vector2::new(1.5, 2.0));
567        assert!(approx_eq(Vector2::ZERO.distance(constructed), 5.0));
568        assert!(approx_eq(Vector2::ZERO.distance_squared(constructed), 25.0));
569        assert_vector2_close(
570            Vector2::ZERO.lerp(Vector2::new(8.0, 4.0), 0.25),
571            Vector2::new(2.0, 1.0),
572        );
573        assert!(Vector2::ZERO.normalize().is_none());
574
575        let normalized = constructed
576            .normalize()
577            .expect("non-zero finite vector should normalize");
578
579        assert_vector2_close(normalized, Vector2::new(0.6, 0.8));
580    }
581
582    #[test]
583    fn vector3_supports_core_operations() {
584        let constructed = Vector3::new(2.0, 3.0, 6.0);
585
586        assert_vector3_close(
587            constructed,
588            Vector3 {
589                x: 2.0,
590                y: 3.0,
591                z: 6.0,
592            },
593        );
594        assert_vector3_close(Vector3::ZERO, Vector3::new(0.0, 0.0, 0.0));
595        assert_vector3_close(Vector3::ONE, Vector3::new(1.0, 1.0, 1.0));
596        assert_vector3_close(constructed + Vector3::ONE, Vector3::new(3.0, 4.0, 7.0));
597        assert_vector3_close(constructed - Vector3::ONE, Vector3::new(1.0, 2.0, 5.0));
598        assert_vector3_close(constructed * 2.0, Vector3::new(4.0, 6.0, 12.0));
599        assert_vector3_close(constructed / 2.0, Vector3::new(1.0, 1.5, 3.0));
600        assert_vector3_close(-constructed, Vector3::new(-2.0, -3.0, -6.0));
601        assert!(approx_eq(
602            constructed.dot(Vector3::new(-1.0, 2.0, 0.5)),
603            7.0
604        ));
605        assert_vector3_close(
606            Vector3::new(1.0, 0.0, 0.0).cross(Vector3::new(0.0, 1.0, 0.0)),
607            Vector3::new(0.0, 0.0, 1.0),
608        );
609        assert!(approx_eq(constructed.magnitude_squared(), 49.0));
610        assert!(approx_eq(constructed.magnitude(), 7.0));
611        assert_vector3_close(constructed.scale(0.5), Vector3::new(1.0, 1.5, 3.0));
612        assert!(approx_eq(Vector3::ZERO.distance(constructed), 7.0));
613        assert!(approx_eq(Vector3::ZERO.distance_squared(constructed), 49.0));
614        assert_vector3_close(
615            Vector3::ZERO.lerp(Vector3::new(4.0, 8.0, 12.0), 0.25),
616            Vector3::new(1.0, 2.0, 3.0),
617        );
618        assert!(Vector3::ZERO.normalize().is_none());
619
620        let normalized = Vector3::new(0.0, 3.0, 4.0)
621            .normalize()
622            .expect("non-zero finite vector should normalize");
623
624        assert_vector3_close(normalized, Vector3::new(0.0, 0.6, 0.8));
625    }
626
627    #[test]
628    fn vector4_supports_core_operations() {
629        let constructed = Vector4::new(2.0, 4.0, 4.0, 4.0);
630
631        assert_vector4_close(
632            constructed,
633            Vector4 {
634                x: 2.0,
635                y: 4.0,
636                z: 4.0,
637                w: 4.0,
638            },
639        );
640        assert_vector4_close(Vector4::ZERO, Vector4::new(0.0, 0.0, 0.0, 0.0));
641        assert_vector4_close(Vector4::ONE, Vector4::new(1.0, 1.0, 1.0, 1.0));
642        assert_vector4_close(constructed + Vector4::ONE, Vector4::new(3.0, 5.0, 5.0, 5.0));
643        assert_vector4_close(constructed - Vector4::ONE, Vector4::new(1.0, 3.0, 3.0, 3.0));
644        assert_vector4_close(constructed * 2.0, Vector4::new(4.0, 8.0, 8.0, 8.0));
645        assert_vector4_close(constructed / 2.0, Vector4::new(1.0, 2.0, 2.0, 2.0));
646        assert_vector4_close(-constructed, Vector4::new(-2.0, -4.0, -4.0, -4.0));
647        assert!(approx_eq(
648            constructed.dot(Vector4::new(1.0, 0.5, 0.5, 0.5)),
649            8.0
650        ));
651        assert!(approx_eq(constructed.magnitude_squared(), 52.0));
652        assert!(approx_eq(constructed.magnitude(), 52.0_f64.sqrt()));
653        assert_vector4_close(constructed.scale(0.5), Vector4::new(1.0, 2.0, 2.0, 2.0));
654        assert!(approx_eq(
655            Vector4::ZERO.distance(Vector4::new(4.0, 4.0, 4.0, 4.0)),
656            8.0
657        ));
658        assert!(approx_eq(
659            Vector4::ZERO.distance_squared(Vector4::new(4.0, 4.0, 4.0, 4.0)),
660            64.0,
661        ));
662        assert_vector4_close(
663            Vector4::ZERO.lerp(Vector4::new(4.0, 8.0, 12.0, 16.0), 0.25),
664            Vector4::new(1.0, 2.0, 3.0, 4.0),
665        );
666        assert!(Vector4::ZERO.normalize().is_none());
667
668        let normalized = Vector4::new(2.0, 0.0, 0.0, 0.0)
669            .normalize()
670            .expect("non-zero finite vector should normalize");
671
672        assert_vector4_close(normalized, Vector4::new(1.0, 0.0, 0.0, 0.0));
673    }
674
675    #[test]
676    fn normalize_rejects_non_finite_magnitudes() {
677        assert!(Vector2::new(f64::INFINITY, 1.0).normalize().is_none());
678        assert!(Vector3::new(f64::NAN, 1.0, 2.0).normalize().is_none());
679        assert!(
680            Vector4::new(f64::MAX, f64::MAX, f64::MAX, f64::MAX)
681                .normalize()
682                .is_none()
683        );
684    }
685}