1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4#[doc(inline)]
7pub use vector2::Vector2;
8#[doc(inline)]
9pub use vector3::Vector3;
10#[doc(inline)]
11pub use vector4::Vector4;
12
13pub 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 #[derive(Debug, Clone, Copy, PartialEq)]
34 pub struct Vector2 {
35 pub x: f64,
37 pub y: f64,
39 }
40
41 impl Vector2 {
42 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
44
45 pub const ONE: Self = Self { x: 1.0, y: 1.0 };
47
48 #[must_use]
50 pub const fn new(x: f64, y: f64) -> Self {
51 Self { x, y }
52 }
53
54 #[must_use]
67 pub fn dot(self, other: Self) -> f64 {
68 dot2(self.x, other.x, self.y, other.y)
69 }
70
71 #[must_use]
73 pub fn magnitude_squared(self) -> f64 {
74 self.dot(self)
75 }
76
77 #[must_use]
79 pub fn magnitude(self) -> f64 {
80 self.magnitude_squared().sqrt()
81 }
82
83 #[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 #[must_use]
112 pub fn scale(self, scalar: f64) -> Self {
113 self * scalar
114 }
115
116 #[must_use]
129 pub fn distance(self, other: Self) -> f64 {
130 (other - self).magnitude()
131 }
132
133 #[must_use]
135 pub fn distance_squared(self, other: Self) -> f64 {
136 (other - self).magnitude_squared()
137 }
138
139 #[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
187pub 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 #[derive(Debug, Clone, Copy, PartialEq)]
213 pub struct Vector3 {
214 pub x: f64,
216 pub y: f64,
218 pub z: f64,
220 }
221
222 impl Vector3 {
223 pub const ZERO: Self = Self {
225 x: 0.0,
226 y: 0.0,
227 z: 0.0,
228 };
229
230 pub const ONE: Self = Self {
232 x: 1.0,
233 y: 1.0,
234 z: 1.0,
235 };
236
237 #[must_use]
239 pub const fn new(x: f64, y: f64, z: f64) -> Self {
240 Self { x, y, z }
241 }
242
243 #[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 #[must_use]
251 pub fn magnitude_squared(self) -> f64 {
252 self.dot(self)
253 }
254
255 #[must_use]
257 pub fn magnitude(self) -> f64 {
258 self.magnitude_squared().sqrt()
259 }
260
261 #[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 #[must_use]
277 pub fn scale(self, scalar: f64) -> Self {
278 self * scalar
279 }
280
281 #[must_use]
283 pub fn distance(self, other: Self) -> f64 {
284 (other - self).magnitude()
285 }
286
287 #[must_use]
289 pub fn distance_squared(self, other: Self) -> f64 {
290 (other - self).magnitude_squared()
291 }
292
293 #[must_use]
295 pub fn lerp(self, other: Self, t: f64) -> Self {
296 self + (other - self) * t
297 }
298
299 #[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
362pub 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 #[derive(Debug, Clone, Copy, PartialEq)]
373 pub struct Vector4 {
374 pub x: f64,
376 pub y: f64,
378 pub z: f64,
380 pub w: f64,
382 }
383
384 impl Vector4 {
385 pub const ZERO: Self = Self {
387 x: 0.0,
388 y: 0.0,
389 z: 0.0,
390 w: 0.0,
391 };
392
393 pub const ONE: Self = Self {
395 x: 1.0,
396 y: 1.0,
397 z: 1.0,
398 w: 1.0,
399 };
400
401 #[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 #[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 #[must_use]
417 pub fn magnitude_squared(self) -> f64 {
418 self.dot(self)
419 }
420
421 #[must_use]
423 pub fn magnitude(self) -> f64 {
424 self.magnitude_squared().sqrt()
425 }
426
427 #[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 #[must_use]
443 pub fn scale(self, scalar: f64) -> Self {
444 self * scalar
445 }
446
447 #[must_use]
449 pub fn distance(self, other: Self) -> f64 {
450 (other - self).magnitude()
451 }
452
453 #[must_use]
455 pub fn distance_squared(self, other: Self) -> f64 {
456 (other - self).magnitude_squared()
457 }
458
459 #[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}