num_quaternion/
arithmetics.rs

1use {
2    crate::{Quaternion, UnitQuaternion, Q32, Q64, UQ32, UQ64},
3    core::ops::{
4        Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
5    },
6    num_traits::{Inv, Num, Zero},
7};
8
9#[cfg(feature = "unstable")]
10use crate::{PureQuaternion, PQ32, PQ64};
11
12impl<T> Add<Quaternion<T>> for Quaternion<T>
13where
14    T: Add<T, Output = T>,
15{
16    type Output = Quaternion<T>;
17
18    #[inline]
19    fn add(self, rhs: Quaternion<T>) -> Self::Output {
20        Self::new(
21            self.w + rhs.w,
22            self.x + rhs.x,
23            self.y + rhs.y,
24            self.z + rhs.z,
25        )
26    }
27}
28
29impl<T> Add<T> for Quaternion<T>
30where
31    T: Add<T, Output = T>,
32{
33    type Output = Quaternion<T>;
34
35    #[inline]
36    fn add(self, rhs: T) -> Self::Output {
37        Self::new(self.w + rhs, self.x, self.y, self.z)
38    }
39}
40
41impl<T> Add<UnitQuaternion<T>> for Quaternion<T>
42where
43    T: Add<T, Output = T>,
44{
45    type Output = Quaternion<T>;
46
47    #[inline]
48    fn add(self, rhs: UnitQuaternion<T>) -> Self {
49        self + rhs.into_inner()
50    }
51}
52
53#[cfg(feature = "unstable")]
54impl<T> Add<PureQuaternion<T>> for Quaternion<T>
55where
56    T: Add<T, Output = T>,
57{
58    type Output = Quaternion<T>;
59
60    #[inline]
61    fn add(self, rhs: PureQuaternion<T>) -> Self::Output {
62        Self::new(self.w, self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
63    }
64}
65
66impl<T> Sub<Quaternion<T>> for Quaternion<T>
67where
68    T: Sub<T, Output = T>,
69{
70    type Output = Quaternion<T>;
71
72    #[inline]
73    fn sub(self, rhs: Quaternion<T>) -> Self::Output {
74        Self::new(
75            self.w - rhs.w,
76            self.x - rhs.x,
77            self.y - rhs.y,
78            self.z - rhs.z,
79        )
80    }
81}
82
83impl<T> Sub<T> for Quaternion<T>
84where
85    T: Sub<T, Output = T>,
86{
87    type Output = Quaternion<T>;
88
89    #[inline]
90    fn sub(self, rhs: T) -> Self::Output {
91        Self::new(self.w - rhs, self.x, self.y, self.z)
92    }
93}
94
95impl<T> Sub<UnitQuaternion<T>> for Quaternion<T>
96where
97    T: Sub<T, Output = T>,
98{
99    type Output = Quaternion<T>;
100
101    #[inline]
102    fn sub(self, rhs: UnitQuaternion<T>) -> Self {
103        self - rhs.into_inner()
104    }
105}
106
107#[cfg(feature = "unstable")]
108impl<T> Sub<PureQuaternion<T>> for Quaternion<T>
109where
110    T: Sub<T, Output = T>,
111{
112    type Output = Quaternion<T>;
113
114    #[inline]
115    fn sub(self, rhs: PureQuaternion<T>) -> Self::Output {
116        Self::new(self.w, self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
117    }
118}
119
120impl<T> Mul<Quaternion<T>> for Quaternion<T>
121where
122    T: Add<T, Output = T> + Sub<T, Output = T> + Mul<T, Output = T> + Clone,
123{
124    type Output = Quaternion<T>;
125
126    #[inline]
127    fn mul(self, rhs: Quaternion<T>) -> Self::Output {
128        let a = self.w.clone() * rhs.w.clone()
129            - self.x.clone() * rhs.x.clone()
130            - self.y.clone() * rhs.y.clone()
131            - self.z.clone() * rhs.z.clone();
132        let b = self.w.clone() * rhs.x.clone()
133            + self.x.clone() * rhs.w.clone()
134            + self.y.clone() * rhs.z.clone()
135            - self.z.clone() * rhs.y.clone();
136        let c = self.w.clone() * rhs.y.clone() - self.x.clone() * rhs.z.clone()
137            + self.y.clone() * rhs.w.clone()
138            + self.z.clone() * rhs.x.clone();
139        let d =
140            self.w * rhs.z + self.x * rhs.y - self.y * rhs.x + self.z * rhs.w;
141        Self::new(a, b, c, d)
142    }
143}
144
145impl<T> Mul<T> for Quaternion<T>
146where
147    T: Mul<T, Output = T> + Clone,
148{
149    type Output = Quaternion<T>;
150
151    #[inline]
152    fn mul(self, rhs: T) -> Self::Output {
153        Self::new(
154            self.w * rhs.clone(),
155            self.x * rhs.clone(),
156            self.y * rhs.clone(),
157            self.z * rhs,
158        )
159    }
160}
161
162impl<T> Mul<UnitQuaternion<T>> for Quaternion<T>
163where
164    Quaternion<T>: Mul<Output = Quaternion<T>>,
165{
166    type Output = Quaternion<T>;
167
168    #[inline]
169    fn mul(self, rhs: UnitQuaternion<T>) -> Self::Output {
170        self * rhs.into_inner()
171    }
172}
173
174#[cfg(feature = "unstable")]
175impl<T> Mul<PureQuaternion<T>> for Quaternion<T>
176where
177    T: Neg<Output = T>
178        + Add<T, Output = T>
179        + Sub<T, Output = T>
180        + Mul<T, Output = T>
181        + Neg<Output = T>
182        + Clone,
183{
184    type Output = Quaternion<T>;
185
186    #[inline]
187    #[rustfmt::skip]
188    fn mul(self, rhs: PureQuaternion<T>) -> Self::Output {
189        let a = - self.x.clone() * rhs.x.clone()
190                   - self.y.clone() * rhs.y.clone()
191                   - self.z.clone() * rhs.z.clone();
192        let b =   self.w.clone() * rhs.x.clone()
193                   + self.y.clone() * rhs.z.clone()
194                   - self.z.clone() * rhs.y.clone();
195        let c =   self.w.clone() * rhs.y.clone()
196                   - self.x.clone() * rhs.z.clone()
197                   + self.z.clone() * rhs.x.clone();
198        let d =   self.w         * rhs.z
199                   + self.x         * rhs.y
200                   - self.y         * rhs.x;
201        Self::new(a, b, c, d)
202    }
203}
204
205impl<T> Div<Quaternion<T>> for Quaternion<T>
206where
207    T: Num + Clone + Neg<Output = T>,
208{
209    type Output = Quaternion<T>;
210
211    #[allow(clippy::suspicious_arithmetic_impl)]
212    #[inline]
213    fn div(self, rhs: Quaternion<T>) -> Self {
214        self * rhs.inv()
215    }
216}
217
218impl<T> Div<T> for Quaternion<T>
219where
220    T: Div<T, Output = T> + Clone,
221{
222    type Output = Quaternion<T>;
223
224    #[inline]
225    fn div(self, rhs: T) -> Self::Output {
226        Self::new(
227            self.w / rhs.clone(),
228            self.x / rhs.clone(),
229            self.y / rhs.clone(),
230            self.z / rhs,
231        )
232    }
233}
234
235impl<T> Div<UnitQuaternion<T>> for Quaternion<T>
236where
237    Quaternion<T>: Mul<Output = Quaternion<T>>,
238    T: Neg<Output = T> + Clone,
239{
240    type Output = Quaternion<T>;
241
242    #[allow(clippy::suspicious_arithmetic_impl)]
243    #[inline]
244    fn div(self, rhs: UnitQuaternion<T>) -> Self::Output {
245        self * rhs.into_inner().conj()
246    }
247}
248
249#[cfg(feature = "unstable")]
250impl<T> Div<PureQuaternion<T>> for Quaternion<T>
251where
252    T: Num + Clone + Neg<Output = T>,
253{
254    type Output = Quaternion<T>;
255
256    #[allow(clippy::suspicious_arithmetic_impl)]
257    #[inline]
258    fn div(self, rhs: PureQuaternion<T>) -> Self::Output {
259        self * rhs.inv()
260    }
261}
262
263macro_rules! impl_bin_op_assign {
264    (impl $bin_op_assign_trait:ident::$bin_op_assign:ident as $bin_op_trait:ident::$bin_op:ident for $generic:ident) => {
265        impl<T, S> $bin_op_assign_trait<S> for $generic<T>
266        where
267            Self: $bin_op_trait<S, Output = Self> + Clone,
268        {
269            #[inline]
270            fn $bin_op_assign(&mut self, other: S) {
271                *self = self.clone().$bin_op(other);
272            }
273        }
274    };
275}
276
277impl_bin_op_assign!(impl AddAssign::add_assign as Add::add for Quaternion);
278impl_bin_op_assign!(impl SubAssign::sub_assign as Sub::sub for Quaternion);
279impl_bin_op_assign!(impl MulAssign::mul_assign as Mul::mul for Quaternion);
280impl_bin_op_assign!(impl DivAssign::div_assign as Div::div for Quaternion);
281
282macro_rules! impl_op_with_ref {
283    (impl<$T:ident> $bin_op_trait:ident::$bin_op:ident for $lhs_type:ty, $rhs_type:ty) => {
284        impl<$T> $bin_op_trait<&$rhs_type> for $lhs_type
285        where
286            Self: $bin_op_trait<$rhs_type>,
287            $rhs_type: Clone,
288        {
289            type Output = <Self as $bin_op_trait<$rhs_type>>::Output;
290
291            fn $bin_op(self, rhs: &$rhs_type) -> Self::Output {
292                self.$bin_op(rhs.clone())
293            }
294        }
295
296        impl<$T> $bin_op_trait<&$rhs_type> for &$lhs_type
297        where
298            $lhs_type: $bin_op_trait<$rhs_type> + Clone,
299            $rhs_type: Clone,
300        {
301            type Output = <$lhs_type as $bin_op_trait<$rhs_type>>::Output;
302
303            fn $bin_op(self, rhs: &$rhs_type) -> Self::Output {
304                self.clone().$bin_op(rhs.clone())
305            }
306        }
307
308        impl<$T> $bin_op_trait<$rhs_type> for &$lhs_type
309        where
310            $lhs_type: $bin_op_trait<$rhs_type> + Clone,
311        {
312            type Output = <$lhs_type as $bin_op_trait<$rhs_type>>::Output;
313
314            fn $bin_op(self, rhs: $rhs_type) -> Self::Output {
315                self.clone().$bin_op(rhs)
316            }
317        }
318    };
319}
320
321impl_op_with_ref!(impl<T> Add::add for Quaternion<T>, Quaternion<T>);
322impl_op_with_ref!(impl<T> Sub::sub for Quaternion<T>, Quaternion<T>);
323impl_op_with_ref!(impl<T> Mul::mul for Quaternion<T>, Quaternion<T>);
324impl_op_with_ref!(impl<T> Div::div for Quaternion<T>, Quaternion<T>);
325impl_op_with_ref!(impl<T> Add::add for Quaternion<T>, UnitQuaternion<T>);
326impl_op_with_ref!(impl<T> Sub::sub for Quaternion<T>, UnitQuaternion<T>);
327impl_op_with_ref!(impl<T> Mul::mul for Quaternion<T>, UnitQuaternion<T>);
328impl_op_with_ref!(impl<T> Div::div for Quaternion<T>, UnitQuaternion<T>);
329impl_op_with_ref!(impl<T> Add::add for Quaternion<T>, T);
330impl_op_with_ref!(impl<T> Sub::sub for Quaternion<T>, T);
331impl_op_with_ref!(impl<T> Mul::mul for Quaternion<T>, T);
332impl_op_with_ref!(impl<T> Div::div for Quaternion<T>, T);
333#[cfg(feature = "unstable")]
334impl_op_with_ref!(impl<T> Add::add for Quaternion<T>, PureQuaternion<T>);
335#[cfg(feature = "unstable")]
336impl_op_with_ref!(impl<T> Sub::sub for Quaternion<T>, PureQuaternion<T>);
337#[cfg(feature = "unstable")]
338impl_op_with_ref!(impl<T> Mul::mul for Quaternion<T>, PureQuaternion<T>);
339#[cfg(feature = "unstable")]
340impl_op_with_ref!(impl<T> Div::div for Quaternion<T>, PureQuaternion<T>);
341
342macro_rules! impl_ops_lhs_real {
343    ($($real:ty),*) => {
344        $(
345        impl Add<Quaternion<$real>> for $real {
346            type Output = Quaternion<$real>;
347
348            #[inline]
349            fn add(self, mut rhs: Quaternion<$real>) -> Self::Output {
350                rhs.w += self;
351                rhs
352            }
353        }
354
355        impl Sub<Quaternion<$real>> for $real {
356            type Output = Quaternion<$real>;
357
358            #[inline]
359            fn sub(self, rhs: Quaternion<$real>) -> Self::Output {
360                let zero = <$real>::zero();
361                Quaternion::new(self - rhs.w, zero - rhs.x, zero - rhs.y, zero - rhs.z)
362            }
363        }
364
365        impl Mul<Quaternion<$real>> for $real {
366            type Output = Quaternion<$real>;
367
368            #[inline]
369            fn mul(self, rhs: Quaternion<$real>) -> Self::Output {
370                Quaternion::new(self * rhs.w, self * rhs.x, self * rhs.y, self * rhs.z)
371            }
372        }
373    )*
374    };
375}
376
377impl_ops_lhs_real!(
378    usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64
379);
380
381impl Div<Q32> for f32 {
382    type Output = Q32;
383
384    #[inline]
385    fn div(mut self, rhs: Q32) -> Self::Output {
386        self /= rhs.norm_sqr();
387        Quaternion::new(
388            self * rhs.w,
389            self * -rhs.x,
390            self * -rhs.y,
391            self * -rhs.z,
392        )
393    }
394}
395
396impl Div<Q64> for f64 {
397    type Output = Q64;
398
399    #[inline]
400    fn div(mut self, rhs: Q64) -> Self::Output {
401        self /= rhs.norm_sqr();
402        Quaternion::new(
403            self * rhs.w,
404            self * -rhs.x,
405            self * -rhs.y,
406            self * -rhs.z,
407        )
408    }
409}
410
411impl<T> Neg for Quaternion<T>
412where
413    T: Neg<Output = T>,
414{
415    type Output = Self;
416
417    #[inline]
418    fn neg(self) -> Self::Output {
419        Self::new(-self.w, -self.x, -self.y, -self.z)
420    }
421}
422
423impl<T> Add<UnitQuaternion<T>> for UnitQuaternion<T>
424where
425    Quaternion<T>: Add<Output = Quaternion<T>>,
426{
427    type Output = Quaternion<T>;
428
429    #[inline]
430    fn add(self, rhs: UnitQuaternion<T>) -> Self::Output {
431        self.into_inner() + rhs.into_inner()
432    }
433}
434
435impl<T> Add<Quaternion<T>> for UnitQuaternion<T>
436where
437    Quaternion<T>: Add<Output = Quaternion<T>>,
438{
439    type Output = Quaternion<T>;
440
441    #[inline]
442    fn add(self, rhs: Quaternion<T>) -> Self::Output {
443        self.into_inner() + rhs
444    }
445}
446
447impl<T> Add<T> for UnitQuaternion<T>
448where
449    Quaternion<T>: Add<T, Output = Quaternion<T>>,
450{
451    type Output = Quaternion<T>;
452
453    #[inline]
454    fn add(self, rhs: T) -> Self::Output {
455        self.into_inner() + rhs
456    }
457}
458
459impl Add<UQ32> for f32 {
460    type Output = Q32;
461
462    #[inline]
463    fn add(self, rhs: UQ32) -> Self::Output {
464        self + rhs.into_inner()
465    }
466}
467
468impl Add<UQ64> for f64 {
469    type Output = Q64;
470
471    #[inline]
472    fn add(self, rhs: UQ64) -> Self::Output {
473        self + rhs.into_inner()
474    }
475}
476
477#[cfg(feature = "unstable")]
478impl<T> Add<PureQuaternion<T>> for UnitQuaternion<T>
479where
480    Quaternion<T>: Add<PureQuaternion<T>, Output = Quaternion<T>>,
481{
482    type Output = Quaternion<T>;
483
484    #[inline]
485    fn add(self, rhs: PureQuaternion<T>) -> Self::Output {
486        self.into_inner() + rhs
487    }
488}
489
490impl<T> Sub<UnitQuaternion<T>> for UnitQuaternion<T>
491where
492    Quaternion<T>: Sub<Output = Quaternion<T>>,
493{
494    type Output = Quaternion<T>;
495
496    #[inline]
497    fn sub(self, rhs: UnitQuaternion<T>) -> Self::Output {
498        self.into_inner() - rhs.into_inner()
499    }
500}
501
502impl<T> Sub<Quaternion<T>> for UnitQuaternion<T>
503where
504    Quaternion<T>: Sub<Output = Quaternion<T>>,
505{
506    type Output = Quaternion<T>;
507
508    #[inline]
509    fn sub(self, rhs: Quaternion<T>) -> Self::Output {
510        self.into_inner() - rhs
511    }
512}
513
514impl<T> Sub<T> for UnitQuaternion<T>
515where
516    Quaternion<T>: Sub<T, Output = Quaternion<T>>,
517{
518    type Output = Quaternion<T>;
519
520    #[inline]
521    fn sub(self, rhs: T) -> Self::Output {
522        self.into_inner() - rhs
523    }
524}
525
526impl Sub<UQ32> for f32 {
527    type Output = Q32;
528
529    #[inline]
530    fn sub(self, rhs: UQ32) -> Self::Output {
531        self - rhs.into_inner()
532    }
533}
534
535impl Sub<UQ64> for f64 {
536    type Output = Q64;
537
538    #[inline]
539    fn sub(self, rhs: UQ64) -> Self::Output {
540        self - rhs.into_inner()
541    }
542}
543
544#[cfg(feature = "unstable")]
545impl<T> Sub<PureQuaternion<T>> for UnitQuaternion<T>
546where
547    Quaternion<T>: Sub<PureQuaternion<T>, Output = Quaternion<T>>,
548{
549    type Output = Quaternion<T>;
550
551    #[inline]
552    fn sub(self, rhs: PureQuaternion<T>) -> Self::Output {
553        self.into_inner() - rhs
554    }
555}
556
557impl<T> Mul<Quaternion<T>> for UnitQuaternion<T>
558where
559    Quaternion<T>: Mul<Output = Quaternion<T>>,
560{
561    type Output = Quaternion<T>;
562
563    #[inline]
564    fn mul(self, rhs: Quaternion<T>) -> Self::Output {
565        self.into_inner() * rhs
566    }
567}
568
569impl<T> Mul<T> for UnitQuaternion<T>
570where
571    Quaternion<T>: Mul<T, Output = Quaternion<T>>,
572{
573    type Output = Quaternion<T>;
574
575    #[inline]
576    fn mul(self, rhs: T) -> Self::Output {
577        self.into_inner() * rhs
578    }
579}
580
581impl Mul<UQ32> for f32 {
582    type Output = Q32;
583
584    #[inline]
585    fn mul(self, rhs: UQ32) -> Self::Output {
586        self * rhs.into_inner()
587    }
588}
589
590impl Mul<UQ64> for f64 {
591    type Output = Q64;
592
593    #[inline]
594    fn mul(self, rhs: UQ64) -> Self::Output {
595        self * rhs.into_inner()
596    }
597}
598
599#[cfg(feature = "unstable")]
600impl<T> Mul<PureQuaternion<T>> for UnitQuaternion<T>
601where
602    Quaternion<T>: Mul<PureQuaternion<T>, Output = Quaternion<T>>,
603{
604    type Output = Quaternion<T>;
605
606    #[inline]
607    fn mul(self, rhs: PureQuaternion<T>) -> Self::Output {
608        self.into_inner() * rhs
609    }
610}
611
612impl<T> Div<UnitQuaternion<T>> for UnitQuaternion<T>
613where
614    Quaternion<T>: Mul<Output = Quaternion<T>>,
615    T: Clone + Neg<Output = T>,
616{
617    type Output = UnitQuaternion<T>;
618
619    #[allow(clippy::suspicious_arithmetic_impl)]
620    #[inline]
621    fn div(self, rhs: UnitQuaternion<T>) -> Self::Output {
622        self * rhs.conj()
623    }
624}
625
626impl<T> Div<Quaternion<T>> for UnitQuaternion<T>
627where
628    Quaternion<T>: Div<Output = Quaternion<T>>,
629{
630    type Output = Quaternion<T>;
631
632    #[inline]
633    fn div(self, rhs: Quaternion<T>) -> Self::Output {
634        self.into_inner() / rhs
635    }
636}
637
638impl<T> Div<T> for UnitQuaternion<T>
639where
640    Quaternion<T>: Div<T, Output = Quaternion<T>>,
641{
642    type Output = Quaternion<T>;
643
644    #[inline]
645    fn div(self, rhs: T) -> Self::Output {
646        self.into_inner() / rhs
647    }
648}
649
650impl Div<UQ32> for f32 {
651    type Output = Q32;
652
653    #[allow(clippy::suspicious_arithmetic_impl)]
654    #[inline]
655    fn div(self, rhs: UQ32) -> Self::Output {
656        self * rhs.inv().into_inner()
657    }
658}
659
660impl Div<UQ64> for f64 {
661    type Output = Q64;
662
663    #[allow(clippy::suspicious_arithmetic_impl)]
664    #[inline]
665    fn div(self, rhs: UQ64) -> Self::Output {
666        self * rhs.inv().into_inner()
667    }
668}
669
670#[cfg(feature = "unstable")]
671impl<T> Div<PureQuaternion<T>> for UnitQuaternion<T>
672where
673    Quaternion<T>: Div<PureQuaternion<T>, Output = Quaternion<T>>,
674{
675    type Output = Quaternion<T>;
676
677    #[inline]
678    fn div(self, rhs: PureQuaternion<T>) -> Self::Output {
679        self.into_inner() / rhs
680    }
681}
682
683impl_op_with_ref!(impl<T> Add::add for UnitQuaternion<T>, UnitQuaternion<T>);
684impl_op_with_ref!(impl<T> Sub::sub for UnitQuaternion<T>, UnitQuaternion<T>);
685impl_op_with_ref!(impl<T> Mul::mul for UnitQuaternion<T>, UnitQuaternion<T>);
686impl_op_with_ref!(impl<T> Div::div for UnitQuaternion<T>, UnitQuaternion<T>);
687impl_op_with_ref!(impl<T> Add::add for UnitQuaternion<T>, Quaternion<T>);
688impl_op_with_ref!(impl<T> Sub::sub for UnitQuaternion<T>, Quaternion<T>);
689impl_op_with_ref!(impl<T> Mul::mul for UnitQuaternion<T>, Quaternion<T>);
690impl_op_with_ref!(impl<T> Div::div for UnitQuaternion<T>, Quaternion<T>);
691impl_op_with_ref!(impl<T> Add::add for UnitQuaternion<T>, T);
692impl_op_with_ref!(impl<T> Sub::sub for UnitQuaternion<T>, T);
693impl_op_with_ref!(impl<T> Mul::mul for UnitQuaternion<T>, T);
694impl_op_with_ref!(impl<T> Div::div for UnitQuaternion<T>, T);
695#[cfg(feature = "unstable")]
696impl_op_with_ref!(impl<T> Add::add for UnitQuaternion<T>, PureQuaternion<T>);
697#[cfg(feature = "unstable")]
698impl_op_with_ref!(impl<T> Sub::sub for UnitQuaternion<T>, PureQuaternion<T>);
699#[cfg(feature = "unstable")]
700impl_op_with_ref!(impl<T> Mul::mul for UnitQuaternion<T>, PureQuaternion<T>);
701#[cfg(feature = "unstable")]
702impl_op_with_ref!(impl<T> Div::div for UnitQuaternion<T>, PureQuaternion<T>);
703
704impl_bin_op_assign!(impl MulAssign::mul_assign as Mul::mul for UnitQuaternion);
705impl_bin_op_assign!(impl DivAssign::div_assign as Div::div for UnitQuaternion);
706
707#[cfg(feature = "unstable")]
708impl<T> Add<PureQuaternion<T>> for PureQuaternion<T>
709where
710    T: Add<T, Output = T>,
711{
712    type Output = PureQuaternion<T>;
713
714    #[inline]
715    fn add(self, rhs: PureQuaternion<T>) -> Self::Output {
716        Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
717    }
718}
719
720#[cfg(feature = "unstable")]
721impl<T> Add<Quaternion<T>> for PureQuaternion<T>
722where
723    T: Add<T, Output = T>,
724{
725    type Output = Quaternion<T>;
726
727    #[inline]
728    fn add(self, rhs: Quaternion<T>) -> Self::Output {
729        Quaternion::new(rhs.w, self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
730    }
731}
732
733#[cfg(feature = "unstable")]
734impl<T> Add<T> for PureQuaternion<T> {
735    type Output = Quaternion<T>;
736
737    #[inline]
738    fn add(self, rhs: T) -> Self::Output {
739        Self::Output::new(rhs, self.x, self.y, self.z)
740    }
741}
742
743#[cfg(feature = "unstable")]
744impl<T> Add<UnitQuaternion<T>> for PureQuaternion<T>
745where
746    T: Add<T, Output = T>,
747{
748    type Output = Quaternion<T>;
749
750    #[inline]
751    fn add(self, rhs: UnitQuaternion<T>) -> Self::Output {
752        self + rhs.into_inner()
753    }
754}
755
756#[cfg(feature = "unstable")]
757impl Add<PQ32> for f32 {
758    type Output = Q32;
759
760    #[inline]
761    fn add(self, rhs: PQ32) -> Self::Output {
762        Self::Output::new(self, rhs.x, rhs.y, rhs.z)
763    }
764}
765
766#[cfg(feature = "unstable")]
767impl Add<PQ64> for f64 {
768    type Output = Q64;
769
770    #[inline]
771    fn add(self, rhs: PQ64) -> Self::Output {
772        Self::Output::new(self, rhs.x, rhs.y, rhs.z)
773    }
774}
775
776#[cfg(feature = "unstable")]
777impl<T> Sub<PureQuaternion<T>> for PureQuaternion<T>
778where
779    T: Sub<T, Output = T>,
780{
781    type Output = PureQuaternion<T>;
782
783    #[inline]
784    fn sub(self, rhs: PureQuaternion<T>) -> Self::Output {
785        Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
786    }
787}
788
789#[cfg(feature = "unstable")]
790impl<T> Sub<Quaternion<T>> for PureQuaternion<T>
791where
792    T: Sub<T, Output = T> + Neg<Output = T>,
793{
794    type Output = Quaternion<T>;
795
796    #[inline]
797    fn sub(self, rhs: Quaternion<T>) -> Self::Output {
798        Quaternion::new(-rhs.w, self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
799    }
800}
801
802#[cfg(feature = "unstable")]
803impl<T> Sub<T> for PureQuaternion<T>
804where
805    T: Neg<Output = T>,
806{
807    type Output = Quaternion<T>;
808
809    #[inline]
810    fn sub(self, rhs: T) -> Self::Output {
811        Self::Output::new(-rhs, self.x, self.y, self.z)
812    }
813}
814
815#[cfg(feature = "unstable")]
816impl<T> Sub<UnitQuaternion<T>> for PureQuaternion<T>
817where
818    T: Sub<T, Output = T> + Neg<Output = T>,
819{
820    type Output = Quaternion<T>;
821
822    #[inline]
823    fn sub(self, rhs: UnitQuaternion<T>) -> Self::Output {
824        self - rhs.into_inner()
825    }
826}
827
828#[cfg(feature = "unstable")]
829impl Sub<PQ32> for f32 {
830    type Output = Q32;
831
832    #[inline]
833    fn sub(self, rhs: PQ32) -> Self::Output {
834        Self::Output::new(self, -rhs.x, -rhs.y, -rhs.z)
835    }
836}
837
838#[cfg(feature = "unstable")]
839impl Sub<PQ64> for f64 {
840    type Output = Q64;
841
842    #[inline]
843    fn sub(self, rhs: PQ64) -> Self::Output {
844        Self::Output::new(self, -rhs.x, -rhs.y, -rhs.z)
845    }
846}
847
848#[cfg(feature = "unstable")]
849impl<T> Mul<PureQuaternion<T>> for PureQuaternion<T>
850where
851    T: Neg<Output = T>
852        + Add<T, Output = T>
853        + Sub<T, Output = T>
854        + Mul<T, Output = T>
855        + Clone,
856{
857    type Output = Quaternion<T>;
858
859    #[inline]
860    #[rustfmt::skip]
861    fn mul(self, rhs: PureQuaternion<T>) -> Self::Output {
862        Quaternion::new(
863          -(self.x.clone() * rhs.x.clone() + self.y.clone() * rhs.y.clone() + self.z.clone() * rhs.z.clone()),
864            self.y.clone() * rhs.z.clone() - self.z.clone() * rhs.y.clone(),
865            self.z.clone() * rhs.x.clone() - self.x.clone() * rhs.z.clone(),
866            self.x.clone() * rhs.y.clone() - self.y.clone() * rhs.x.clone(),
867        )
868    }
869}
870
871#[cfg(feature = "unstable")]
872impl<T> Mul<Quaternion<T>> for PureQuaternion<T>
873where
874    T: Neg<Output = T>
875        + Add<T, Output = T>
876        + Sub<T, Output = T>
877        + Mul<T, Output = T>
878        + Clone,
879{
880    type Output = Quaternion<T>;
881
882    #[inline]
883    #[rustfmt::skip]
884    fn mul(self, rhs: Quaternion<T>) -> Self::Output {
885        let a = - self.x.clone() * rhs.x.clone()
886                   - self.y.clone() * rhs.y.clone()
887                   - self.z.clone() * rhs.z.clone();
888        let b =   self.x.clone() * rhs.w.clone()
889                   + self.y.clone() * rhs.z.clone()
890                   - self.z.clone() * rhs.y.clone();
891        let c = - self.x.clone() * rhs.z.clone()
892                   + self.y.clone() * rhs.w.clone()
893                   + self.z.clone() * rhs.x.clone();
894        let d =   self.x         * rhs.y
895                   - self.y         * rhs.x
896                   + self.z         * rhs.w;
897        Self::Output::new(a, b, c, d)
898    }
899}
900
901#[cfg(feature = "unstable")]
902impl<T> Mul<T> for PureQuaternion<T>
903where
904    T: Mul<T, Output = T> + Clone,
905{
906    type Output = PureQuaternion<T>;
907
908    #[inline]
909    #[rustfmt::skip]
910    fn mul(self, rhs: T) -> Self::Output {
911        Self::new(self.x * rhs.clone(),
912                  self.y * rhs.clone(),
913                  self.z * rhs)
914    }
915}
916
917#[cfg(feature = "unstable")]
918impl<T> Mul<UnitQuaternion<T>> for PureQuaternion<T>
919where
920    PureQuaternion<T>: Mul<Quaternion<T>, Output = Quaternion<T>>,
921{
922    type Output = Quaternion<T>;
923
924    #[inline]
925    fn mul(self, rhs: UnitQuaternion<T>) -> Self::Output {
926        self * rhs.into_inner()
927    }
928}
929
930#[cfg(feature = "unstable")]
931impl Mul<PQ32> for f32 {
932    type Output = PQ32;
933
934    #[inline]
935    #[rustfmt::skip]
936    fn mul(self, rhs: PQ32) -> Self::Output {
937        Self::Output::new(self * rhs.x,
938                          self * rhs.y,
939                          self * rhs.z)
940    }
941}
942
943#[cfg(feature = "unstable")]
944impl Mul<PQ64> for f64 {
945    type Output = PQ64;
946
947    #[inline]
948    #[rustfmt::skip]
949    fn mul(self, rhs: PQ64) -> Self::Output {
950        Self::Output::new(self * rhs.x,
951                          self * rhs.y,
952                          self * rhs.z)
953    }
954}
955
956#[cfg(feature = "unstable")]
957impl<T> Div<PureQuaternion<T>> for PureQuaternion<T>
958where
959    T: Num + Clone + Neg<Output = T>,
960{
961    type Output = Quaternion<T>;
962
963    #[allow(clippy::suspicious_arithmetic_impl)]
964    #[inline]
965    fn div(self, rhs: PureQuaternion<T>) -> Self::Output {
966        self * rhs.inv()
967    }
968}
969
970#[cfg(feature = "unstable")]
971impl<T> Div<Quaternion<T>> for PureQuaternion<T>
972where
973    T: Num + Clone + Neg<Output = T>,
974{
975    type Output = Quaternion<T>;
976
977    #[allow(clippy::suspicious_arithmetic_impl)]
978    #[inline]
979    fn div(self, rhs: Quaternion<T>) -> Self::Output {
980        self * rhs.inv()
981    }
982}
983
984#[cfg(feature = "unstable")]
985impl<T> Div<T> for PureQuaternion<T>
986where
987    T: Div<T, Output = T> + Clone,
988{
989    type Output = PureQuaternion<T>;
990
991    #[inline]
992    fn div(self, rhs: T) -> Self::Output {
993        Self::new(self.x / rhs.clone(), self.y / rhs.clone(), self.z / rhs)
994    }
995}
996
997#[cfg(feature = "unstable")]
998impl<T> Div<UnitQuaternion<T>> for PureQuaternion<T>
999where
1000    T: Num + Clone + Neg<Output = T>,
1001{
1002    type Output = Quaternion<T>;
1003
1004    #[allow(clippy::suspicious_arithmetic_impl)]
1005    #[inline]
1006    fn div(self, rhs: UnitQuaternion<T>) -> Self::Output {
1007        self * rhs.inv()
1008    }
1009}
1010
1011#[cfg(feature = "unstable")]
1012impl Div<PQ32> for f32 {
1013    type Output = PQ32;
1014
1015    #[allow(clippy::suspicious_arithmetic_impl)]
1016    #[inline]
1017    fn div(self, rhs: PQ32) -> Self::Output {
1018        self * rhs.inv()
1019    }
1020}
1021
1022#[cfg(feature = "unstable")]
1023impl Div<PQ64> for f64 {
1024    type Output = PQ64;
1025
1026    #[allow(clippy::suspicious_arithmetic_impl)]
1027    #[inline]
1028    fn div(self, rhs: PQ64) -> Self::Output {
1029        self * rhs.inv()
1030    }
1031}
1032
1033#[cfg(feature = "unstable")]
1034impl_op_with_ref!(impl<T> Add::add for PureQuaternion<T>, PureQuaternion<T>);
1035#[cfg(feature = "unstable")]
1036impl_op_with_ref!(impl<T> Sub::sub for PureQuaternion<T>, PureQuaternion<T>);
1037#[cfg(feature = "unstable")]
1038impl_op_with_ref!(impl<T> Mul::mul for PureQuaternion<T>, PureQuaternion<T>);
1039#[cfg(feature = "unstable")]
1040impl_op_with_ref!(impl<T> Div::div for PureQuaternion<T>, PureQuaternion<T>);
1041#[cfg(feature = "unstable")]
1042impl_op_with_ref!(impl<T> Add::add for PureQuaternion<T>, Quaternion<T>);
1043#[cfg(feature = "unstable")]
1044impl_op_with_ref!(impl<T> Sub::sub for PureQuaternion<T>, Quaternion<T>);
1045#[cfg(feature = "unstable")]
1046impl_op_with_ref!(impl<T> Mul::mul for PureQuaternion<T>, Quaternion<T>);
1047#[cfg(feature = "unstable")]
1048impl_op_with_ref!(impl<T> Div::div for PureQuaternion<T>, Quaternion<T>);
1049#[cfg(feature = "unstable")]
1050impl_op_with_ref!(impl<T> Add::add for PureQuaternion<T>, T);
1051#[cfg(feature = "unstable")]
1052impl_op_with_ref!(impl<T> Sub::sub for PureQuaternion<T>, T);
1053#[cfg(feature = "unstable")]
1054impl_op_with_ref!(impl<T> Mul::mul for PureQuaternion<T>, T);
1055#[cfg(feature = "unstable")]
1056impl_op_with_ref!(impl<T> Div::div for PureQuaternion<T>, T);
1057#[cfg(feature = "unstable")]
1058impl_op_with_ref!(impl<T> Add::add for PureQuaternion<T>, UnitQuaternion<T>);
1059#[cfg(feature = "unstable")]
1060impl_op_with_ref!(impl<T> Sub::sub for PureQuaternion<T>, UnitQuaternion<T>);
1061#[cfg(feature = "unstable")]
1062impl_op_with_ref!(impl<T> Mul::mul for PureQuaternion<T>, UnitQuaternion<T>);
1063#[cfg(feature = "unstable")]
1064impl_op_with_ref!(impl<T> Div::div for PureQuaternion<T>, UnitQuaternion<T>);
1065
1066#[cfg(feature = "unstable")]
1067impl_bin_op_assign!(impl AddAssign::add_assign as Add::add for PureQuaternion);
1068#[cfg(feature = "unstable")]
1069impl_bin_op_assign!(impl SubAssign::sub_assign as Sub::sub for PureQuaternion);
1070#[cfg(feature = "unstable")]
1071impl_bin_op_assign!(impl MulAssign::mul_assign as Mul::mul for PureQuaternion);
1072#[cfg(feature = "unstable")]
1073impl_bin_op_assign!(impl DivAssign::div_assign as Div::div for PureQuaternion);
1074
1075#[cfg(test)]
1076mod tests {
1077
1078    use crate::{Quaternion, Q32, Q64, UQ32, UQ64};
1079    #[cfg(feature = "unstable")]
1080    use crate::{PQ32, PQ64};
1081
1082    #[test]
1083    fn test_add_quaternion() {
1084        // Test the addition of quaternions
1085        assert_eq!(Q32::ONE + Q32::J, Q32::new(1.0, 0.0, 1.0, 0.0));
1086        assert_eq!(
1087            Q64::new(1.0, 2.0, 3.0, 4.0) + Q64::new(1.0, 3.0, 10.0, -5.0),
1088            Q64::new(2.0, 5.0, 13.0, -1.0)
1089        );
1090    }
1091
1092    #[test]
1093    fn test_add_real() {
1094        // Test the addition of a real number to a quaternion
1095        assert_eq!(Q32::I + 1.0, Q32::new(1.0, 1.0, 0.0, 0.0));
1096        assert_eq!(
1097            Q32::new(1.0, 2.0, 3.0, 4.0) + 42.0,
1098            Q32::new(43.0, 2.0, 3.0, 4.0)
1099        );
1100    }
1101
1102    #[test]
1103    fn test_add_quaternion_and_unit_quaternion() {
1104        // Test the addition of a quaternion and a unit quaternion
1105        assert_eq!(Q32::I + UQ32::J, Q32::new(0.0, 1.0, 1.0, 0.0));
1106        assert_eq!(
1107            Q64::new(1.0, 2.0, 3.0, 4.0) + UQ64::K,
1108            Q64::new(1.0, 2.0, 3.0, 5.0)
1109        );
1110    }
1111
1112    #[test]
1113    #[cfg(feature = "unstable")]
1114    fn test_add_quaternion_and_pure_quaternion() {
1115        // Test the addition of a quaternion and a pure quaternion
1116        assert_eq!(
1117            Q32::I + PQ32::new(1.0, 2.0, 3.0),
1118            Q32::new(0.0, 2.0, 2.0, 3.0)
1119        );
1120        assert_eq!(
1121            Q64::new(1.0, 2.0, 3.0, 4.0) + PQ64::new(1.0, 3.0, 10.0),
1122            Q64::new(1.0, 3.0, 6.0, 14.0)
1123        );
1124    }
1125
1126    #[test]
1127    fn test_sub_quaternion() {
1128        // Test the subtraction of quaternions
1129        assert_eq!(Q32::ONE - Q32::J, Q32::new(1.0, 0.0, -1.0, 0.0));
1130        assert_eq!(
1131            Q64::new(1.0, 2.0, 3.0, 4.0) - Q64::new(1.0, 3.0, 10.0, -5.0),
1132            Q64::new(0.0, -1.0, -7.0, 9.0)
1133        );
1134    }
1135
1136    #[test]
1137    fn test_sub_real() {
1138        // Test the subtraction of a real number from a quaternion
1139        assert_eq!(Q32::I - 1.0, Q32::new(-1.0, 1.0, 0.0, 0.0));
1140        assert_eq!(
1141            Q32::new(1.0, 2.0, 3.0, 4.0) - 42.0,
1142            Q32::new(-41.0, 2.0, 3.0, 4.0)
1143        );
1144    }
1145
1146    #[test]
1147    #[cfg(feature = "unstable")]
1148    fn test_sub_quaternion_and_unit_quaternion() {
1149        // Test the subtraction of a quaternion and a unit quaternion
1150        assert_eq!(Q32::I - UQ32::J, Q32::new(0.0, 1.0, -1.0, 0.0));
1151        assert_eq!(
1152            Q64::new(1.0, 2.0, 3.0, 4.0) - UQ64::K,
1153            Q64::new(1.0, 2.0, 3.0, 3.0)
1154        );
1155    }
1156
1157    #[test]
1158    fn test_mul_quaternion() {
1159        // Test the multiplication of quaternions
1160        assert_eq!(Q32::ONE * Q32::ONE, Q32::ONE);
1161        assert_eq!(Q32::ONE * Q32::I, Q32::I);
1162        assert_eq!(Q32::ONE * Q32::J, Q32::J);
1163        assert_eq!(Q32::ONE * Q32::K, Q32::K);
1164        assert_eq!(Q32::I * Q32::ONE, Q32::I);
1165        assert_eq!(Q32::J * Q32::ONE, Q32::J);
1166        assert_eq!(Q32::K * Q32::ONE, Q32::K);
1167        assert_eq!(Q32::I * Q32::I, -Q32::ONE);
1168        assert_eq!(Q32::J * Q32::J, -Q32::ONE);
1169        assert_eq!(Q32::K * Q32::K, -Q32::ONE);
1170        assert_eq!(Q32::I * Q32::J, Q32::K);
1171        assert_eq!(Q32::J * Q32::K, Q32::I);
1172        assert_eq!(Q32::K * Q32::I, Q32::J);
1173        assert_eq!(Q32::J * Q32::I, -Q32::K);
1174        assert_eq!(Q32::K * Q32::J, -Q32::I);
1175        assert_eq!(Q32::I * Q32::K, -Q32::J);
1176        assert_eq!(
1177            Q64::new(1.0, 2.0, 3.0, 4.0) * Q64::new(1.0, 3.0, 10.0, -5.0),
1178            Q64::new(-15.0, -50.0, 35.0, 10.0)
1179        );
1180    }
1181
1182    #[test]
1183    fn test_mul_real() {
1184        // Test the multiplication of a quaternion by a real number
1185        assert_eq!(Q32::I * 1.0, Q32::I);
1186        assert_eq!(
1187            Q32::new(1.0, 2.0, 3.0, 4.0) * 42.0,
1188            Q32::new(42.0, 84.0, 126.0, 168.0)
1189        );
1190    }
1191
1192    #[test]
1193    fn test_mul_quaternion_by_unit_quaternion() {
1194        // Test the multiplication of a quaternion by a unit quaternion
1195        assert_eq!(Q32::I * UQ32::J, Q32::K);
1196        assert_eq!(Q64::J * UQ64::K, Q64::I);
1197        assert_eq!(
1198            Q32::new(1.0, 2.0, 3.0, 4.0) * UQ32::K,
1199            Q32::new(-4.0, 3.0, -2.0, 1.0)
1200        );
1201    }
1202
1203    #[test]
1204    #[cfg(feature = "unstable")]
1205    fn test_mul_quaternion_by_pure_quaternion() {
1206        // Test the multiplication of a quaternion by a pure quaternion
1207        assert_eq!(
1208            Q32::I * PQ32::new(1.0, 2.0, 3.0),
1209            Q32::new(-1.0, 0.0, -3.0, 2.0)
1210        );
1211        assert_eq!(
1212            Q64::new(1.0, 2.0, 3.0, 4.0) * PQ64::new(1.0, 3.0, 10.0),
1213            Q64::new(1.0, 2.0, 3.0, 4.0) * Q64::new(0.0, 1.0, 3.0, 10.0)
1214        );
1215    }
1216
1217    #[test]
1218    fn test_div_quaternion() {
1219        // Test the division of quaternions
1220        assert_eq!(Q32::ONE / Q32::ONE * Q32::ONE, Q32::ONE);
1221        assert_eq!(Q32::ONE / Q32::I * Q32::I, Q32::ONE);
1222        assert_eq!(Q32::ONE / Q32::J * Q32::J, Q32::ONE);
1223        assert_eq!(Q32::ONE / Q32::K * Q32::K, Q32::ONE);
1224        assert_eq!(Q32::I / Q32::ONE * Q32::ONE, Q32::I);
1225        assert_eq!(Q32::J / Q32::ONE * Q32::ONE, Q32::J);
1226        assert_eq!(Q32::K / Q32::ONE * Q32::ONE, Q32::K);
1227        assert_eq!(Q32::I / Q32::I * Q32::I, Q32::I);
1228        assert_eq!(Q32::J / Q32::J * Q32::J, Q32::J);
1229        assert_eq!(Q32::K / Q32::K * Q32::K, Q32::K);
1230        assert_eq!(Q32::I / Q32::J * Q32::J, Q32::I);
1231        assert_eq!(Q32::J / Q32::K * Q32::K, Q32::J);
1232        assert_eq!(Q32::K / Q32::I * Q32::I, Q32::K);
1233        assert_eq!(Q32::J / Q32::I * Q32::I, Q32::J);
1234        assert_eq!(Q32::K / Q32::J * Q32::J, Q32::K);
1235        assert_eq!(Q32::I / Q32::K * Q32::K, Q32::I);
1236        let q = Q64::new(1.0, 2.0, 3.0, 4.0);
1237        let r = Q64::new(1.0, 3.0, 10.0, -5.0);
1238        assert!((q / r * r - q).norm_sqr() < f64::EPSILON);
1239    }
1240
1241    #[test]
1242    fn test_div_real() {
1243        // Test the division of a quaternion by a real number
1244        assert_eq!(Q32::I * 1.0, Q32::I);
1245        assert_eq!(
1246            Q32::new(1.0, 2.0, 3.0, 4.0) / 4.0,
1247            Q32::new(0.25, 0.5, 0.75, 1.0)
1248        );
1249    }
1250
1251    #[test]
1252    fn test_div_quaternion_by_unit_quaternion() {
1253        // Test the division of a quaternion by a unit quaternion
1254        assert_eq!(Q32::I / UQ32::J, -Q32::K);
1255        assert_eq!(Q64::J / UQ64::K, -Q64::I);
1256        assert_eq!(
1257            Q32::new(1.0, 2.0, 3.0, 4.0) / UQ32::K,
1258            Q32::new(4.0, -3.0, 2.0, -1.0)
1259        );
1260    }
1261
1262    #[test]
1263    #[cfg(feature = "unstable")]
1264    fn test_div_quaternion_by_pure_quaternion() {
1265        // Test the division of a quaternion by a pure quaternion
1266        assert_eq!(
1267            Q32::I / PQ32::new(1.0, 2.0, 3.0),
1268            Q32::new(1.0, 0.0, 3.0, -2.0) / 14.0
1269        );
1270        assert_eq!(
1271            Q64::new(1.0, 2.0, 3.0, 4.0) / PQ64::new(1.0, 3.0, 10.0),
1272            Q64::new(1.0, 2.0, 3.0, 4.0) / Q64::new(0.0, 1.0, 3.0, 10.0)
1273        );
1274    }
1275
1276    #[test]
1277    fn test_add_assign() {
1278        // Test the addition assignment operator
1279        let mut q = Q32::new(1.0, 2.0, 3.0, 4.0);
1280        q += 4.0;
1281        assert_eq!(q, Quaternion::new(5.0, 2.0, 3.0, 4.0));
1282    }
1283
1284    #[test]
1285    fn test_sub_assign() {
1286        // Test the subtraction assignment operator
1287        let mut q = Q64::new(1.0, 2.0, 3.0, 4.0);
1288        q -= Q64::new(4.0, 8.0, 6.0, 1.0);
1289        assert_eq!(q, Quaternion::new(-3.0, -6.0, -3.0, 3.0));
1290    }
1291
1292    #[test]
1293    fn test_mul_assign() {
1294        // Test the multiplication assignment operator
1295        let mut q = Q32::new(1.0, 2.0, 3.0, 4.0);
1296        q *= UQ32::I;
1297        assert_eq!(q, Quaternion::new(-2.0, 1.0, 4.0, -3.0));
1298    }
1299
1300    #[test]
1301    #[cfg(feature = "unstable")]
1302    fn test_div_assign() {
1303        // Test the division assignment operator
1304        let mut q = Quaternion::new(1.0f32, 2.0f32, 3.0f32, 4.0f32);
1305        q /= PQ32::new(4.0f32, 0.0, 0.0);
1306        assert_eq!(q, Quaternion::new(0.5f32, -0.25f32, -1.0f32, 0.75f32));
1307    }
1308
1309    #[test]
1310    #[allow(clippy::op_ref)]
1311    fn test_add_with_ref() {
1312        // Test the addition operator with references
1313        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1314        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1315        assert_eq!(lhs + rhs, &lhs + rhs);
1316        assert_eq!(lhs + rhs, lhs + &rhs);
1317        assert_eq!(lhs + rhs, &lhs + &rhs);
1318    }
1319
1320    #[test]
1321    #[allow(clippy::op_ref)]
1322    fn test_sub_with_ref() {
1323        // Test the subtraction operator with references
1324        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1325        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1326        assert_eq!(lhs - rhs, &lhs - rhs);
1327        assert_eq!(lhs - rhs, lhs - &rhs);
1328        assert_eq!(lhs - rhs, &lhs - &rhs);
1329    }
1330
1331    #[test]
1332    #[allow(clippy::op_ref)]
1333    fn test_mul_with_ref() {
1334        // Test the multiplication operator with references
1335        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1336        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1337        assert_eq!(lhs * rhs, &lhs * rhs);
1338        assert_eq!(lhs * rhs, lhs * &rhs);
1339        assert_eq!(lhs * rhs, &lhs * &rhs);
1340    }
1341
1342    #[test]
1343    #[allow(clippy::op_ref)]
1344    fn test_div_with_ref() {
1345        // Test the division operator with references
1346        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1347        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1348        assert_eq!(lhs / rhs, &lhs / rhs);
1349        assert_eq!(lhs / rhs, lhs / &rhs);
1350        assert_eq!(lhs / rhs, &lhs / &rhs);
1351    }
1352
1353    #[test]
1354    #[cfg(any(feature = "std", feature = "libm"))]
1355    #[allow(clippy::op_ref)]
1356    fn test_add_unit_quaternion_with_ref() {
1357        // Test the addition of a quaternion with a unit quaternion with
1358        // references
1359        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1360        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1361        assert_eq!(lhs + rhs, &lhs + rhs);
1362        assert_eq!(lhs + rhs, lhs + &rhs);
1363        assert_eq!(lhs + rhs, &lhs + &rhs);
1364    }
1365
1366    #[test]
1367    #[cfg(any(feature = "std", feature = "libm"))]
1368    #[allow(clippy::op_ref)]
1369    fn test_sub_unit_quaternion_with_ref() {
1370        // Test the subtraction of a quaternion with a unit quaternion with
1371        // references
1372        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1373        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1374        assert_eq!(lhs - rhs, &lhs - rhs);
1375        assert_eq!(lhs - rhs, lhs - &rhs);
1376        assert_eq!(lhs - rhs, &lhs - &rhs);
1377    }
1378
1379    #[test]
1380    #[cfg(any(feature = "std", feature = "libm"))]
1381    #[allow(clippy::op_ref)]
1382    fn test_mul_unit_quaternion_with_ref() {
1383        // Test the multiplication of a quaternion with a unit quaternion with
1384        // references
1385        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1386        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1387        assert_eq!(lhs * rhs, &lhs * rhs);
1388        assert_eq!(lhs * rhs, lhs * &rhs);
1389        assert_eq!(lhs * rhs, &lhs * &rhs);
1390    }
1391
1392    #[test]
1393    #[cfg(any(feature = "std", feature = "libm"))]
1394    #[allow(clippy::op_ref)]
1395    fn test_div_unit_quaternion_with_ref() {
1396        // Test the division of a quaternion by a unit quaternion with
1397        // references
1398        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1399        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1400        assert_eq!(lhs / rhs, &lhs / rhs);
1401        assert_eq!(lhs / rhs, lhs / &rhs);
1402        assert_eq!(lhs / rhs, &lhs / &rhs);
1403    }
1404
1405    #[test]
1406    #[allow(clippy::op_ref)]
1407    fn test_add_real_with_ref() {
1408        // Test the addition of a real number to a quaternion with
1409        // references
1410        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1411        let rhs = 5.0;
1412        assert_eq!(lhs + rhs, &lhs + rhs);
1413        assert_eq!(lhs + rhs, lhs + &rhs);
1414        assert_eq!(lhs + rhs, &lhs + &rhs);
1415    }
1416
1417    #[test]
1418    #[allow(clippy::op_ref)]
1419    fn test_sub_real_with_ref() {
1420        // Test the subtraction of a real number from a quaternion with
1421        // references
1422        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1423        let rhs = 5.0;
1424        assert_eq!(lhs - rhs, &lhs - rhs);
1425        assert_eq!(lhs - rhs, lhs - &rhs);
1426        assert_eq!(lhs - rhs, &lhs - &rhs);
1427    }
1428
1429    #[test]
1430    #[allow(clippy::op_ref)]
1431    fn test_mul_real_with_ref() {
1432        // Test the multiplication of a quaternion by a real number with
1433        // references
1434        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1435        let rhs = 5.0;
1436        assert_eq!(lhs * rhs, &lhs * rhs);
1437        assert_eq!(lhs * rhs, lhs * &rhs);
1438        assert_eq!(lhs * rhs, &lhs * &rhs);
1439    }
1440
1441    #[test]
1442    #[allow(clippy::op_ref)]
1443    fn test_div_real_with_ref() {
1444        // Test the division of a quaternion by a real number with references
1445        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1446        let rhs = 5.0;
1447        assert_eq!(lhs / rhs, &lhs / rhs);
1448        assert_eq!(lhs / rhs, lhs / &rhs);
1449        assert_eq!(lhs / rhs, &lhs / &rhs);
1450    }
1451
1452    #[test]
1453    #[cfg(feature = "unstable")]
1454    #[allow(clippy::op_ref)]
1455    fn test_add_pure_quaternion_with_ref() {
1456        // Test the addition of a pure quaternion with references
1457        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1458        let rhs = PQ32::new(5.0, 6.0, 7.0);
1459        assert_eq!(lhs + rhs, &lhs + rhs);
1460        assert_eq!(lhs + rhs, lhs + &rhs);
1461        assert_eq!(lhs + rhs, &lhs + &rhs);
1462    }
1463
1464    #[test]
1465    #[cfg(feature = "unstable")]
1466    #[allow(clippy::op_ref)]
1467    fn test_sub_pure_quaternion_with_ref() {
1468        // Test the subtraction of a pure quaternion with references
1469        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1470        let rhs = PQ32::new(5.0, 6.0, 7.0);
1471        assert_eq!(lhs - rhs, &lhs - rhs);
1472        assert_eq!(lhs - rhs, lhs - &rhs);
1473        assert_eq!(lhs - rhs, &lhs - &rhs);
1474    }
1475
1476    #[test]
1477    #[cfg(feature = "unstable")]
1478    #[allow(clippy::op_ref)]
1479    fn test_mul_pure_quaternion_with_ref() {
1480        // Test the multiplication of a pure quaternion with references
1481        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1482        let rhs = PQ32::new(5.0, 6.0, 7.0);
1483        assert_eq!(lhs * rhs, &lhs * rhs);
1484        assert_eq!(lhs * rhs, lhs * &rhs);
1485        assert_eq!(lhs * rhs, &lhs * &rhs);
1486    }
1487
1488    #[test]
1489    #[cfg(feature = "unstable")]
1490    #[allow(clippy::op_ref)]
1491    fn test_div_pure_quaternion_with_ref() {
1492        // Test the division of a pure quaternion with references
1493        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1494        let rhs = PQ32::new(5.0, 6.0, 7.0);
1495        assert_eq!(lhs / rhs, &lhs / rhs);
1496        assert_eq!(lhs / rhs, lhs / &rhs);
1497        assert_eq!(lhs / rhs, &lhs / &rhs);
1498    }
1499
1500    #[test]
1501    fn test_add_lhs_real() {
1502        // Test the addition of a real number to a quaternion
1503        assert_eq!(42.0 + Quaternion::I, Quaternion::new(42.0, 1.0, 0.0, 0.0));
1504        assert_eq!(
1505            1 + Quaternion::new(2, 4, 6, 8),
1506            Quaternion::new(3, 4, 6, 8)
1507        );
1508    }
1509
1510    #[test]
1511    fn test_sub_lhs_real() {
1512        // Test the subtraction of a real number from a quaternion
1513        assert_eq!(42.0 - Quaternion::I, Quaternion::new(42.0, -1.0, 0.0, 0.0));
1514        assert_eq!(
1515            1 - Quaternion::new(2, 4, 6, 8),
1516            Quaternion::new(-1, -4, -6, -8)
1517        );
1518    }
1519
1520    #[test]
1521    fn test_mul_lhs_real() {
1522        // Test the multiplication of a quaternion by a real number
1523        assert_eq!(42.0 * Quaternion::I, Quaternion::new(0.0, 42.0, 0.0, 0.0));
1524        assert_eq!(
1525            2 * Quaternion::new(1, 2, 3, 4),
1526            Quaternion::new(2, 4, 6, 8)
1527        );
1528    }
1529
1530    #[test]
1531    fn test_div_lhs_real() {
1532        // Test the division of a quaternion by a real number{
1533        assert_eq!(
1534            42.0f32 / Quaternion::I,
1535            Quaternion::new(0.0, -42.0, 0.0, 0.0)
1536        );
1537        assert_eq!(
1538            4.0f64 / Quaternion::new(1.0, 1.0, 1.0, 1.0),
1539            Quaternion::new(1.0, -1.0, -1.0, -1.0)
1540        );
1541    }
1542
1543    #[test]
1544    fn test_neg() {
1545        // Test the negation operator
1546        assert_eq!(
1547            -Q64::new(1.0, -2.0, 3.0, -4.0),
1548            Q64::new(-1.0, 2.0, -3.0, 4.0)
1549        );
1550    }
1551
1552    #[test]
1553    fn test_unit_quaternion_add() {
1554        // Test the addition of unit quaternions
1555        assert_eq!(UQ32::I + UQ32::J, Q32::new(0.0, 1.0, 1.0, 0.0));
1556    }
1557
1558    #[test]
1559    fn test_unit_quaternion_add_quaternion() {
1560        // Test the addition of unit quaternions and quaternions
1561        assert_eq!(UQ32::J + Q32::K, Q32::new(0.0, 0.0, 1.0, 1.0));
1562    }
1563
1564    #[test]
1565    fn test_unit_quaternion_add_underlying() {
1566        // Test the addition of unit quaternions and underlying types
1567        assert_eq!(UQ32::J + 2.0f32, Q32::new(2.0, 0.0, 1.0, 0.0));
1568    }
1569
1570    #[test]
1571    fn test_f32_add_unit_quaternion() {
1572        // Test the addition of `f32` values and `f32` unit quaternions
1573        assert_eq!(3.0f32 + UQ32::K, Q32::new(3.0, 0.0, 0.0, 1.0));
1574    }
1575
1576    #[test]
1577    fn test_f64_add_unit_quaternion() {
1578        // Test the addition of `f64` values and `f64` unit quaternions
1579        assert_eq!(4.0f64 + UQ64::I, Q64::new(4.0, 1.0, 0.0, 0.0));
1580    }
1581
1582    #[test]
1583    #[cfg(feature = "unstable")]
1584    fn test_unit_quaternion_add_pure_quaternion() {
1585        // Test the addition of unit quaternions and pure quaternions
1586        assert_eq!(
1587            UQ32::J + PQ32::new(1.0, 2.0, 3.0),
1588            Q32::new(0.0, 1.0, 3.0, 3.0)
1589        );
1590    }
1591
1592    #[test]
1593    fn test_unit_quaternion_sub() {
1594        // Test the subtraction of unit quaternions
1595        assert_eq!(UQ32::I - UQ32::J, Q32::new(0.0, 1.0, -1.0, 0.0));
1596    }
1597
1598    #[test]
1599    fn test_unit_quaternion_sub_quaternion() {
1600        // Test the subtraction of unit quaternions and quaternions
1601        assert_eq!(UQ32::J - Q32::K, Q32::new(0.0, 0.0, 1.0, -1.0));
1602    }
1603
1604    #[test]
1605    fn test_unit_quaternion_sub_underlying() {
1606        // Test the subtraction of unit quaternions and underlying types
1607        assert_eq!(UQ32::J - 2.0f32, Q32::new(-2.0, 0.0, 1.0, 0.0));
1608    }
1609
1610    #[test]
1611    fn test_f32_sub_unit_quaternion() {
1612        // Test the subtraction of `f32` values and `f32` unit quaternions
1613        assert_eq!(3.0f32 - UQ32::K, Q32::new(3.0, 0.0, 0.0, -1.0));
1614    }
1615
1616    #[test]
1617    fn test_f64_sub_unit_quaternion() {
1618        // Test the subtraction of `f64` values and `f64` unit quaternions
1619        assert_eq!(4.0f64 - UQ64::I, Q64::new(4.0, -1.0, 0.0, 0.0));
1620    }
1621
1622    #[test]
1623    #[cfg(feature = "unstable")]
1624    fn test_unit_quaternion_sub_pure_quaternion() {
1625        // Test the subtraction of unit quaternions and pure quaternions
1626        assert_eq!(
1627            UQ32::J - PQ32::new(1.0, 2.0, 3.0),
1628            Q32::new(0.0, -1.0, -1.0, -3.0)
1629        );
1630    }
1631
1632    #[test]
1633    fn test_unit_quaternion_mul() {
1634        // Test the multiplication of unit quaternions
1635        assert_eq!(UQ32::I * UQ32::J, UQ32::K);
1636    }
1637
1638    #[test]
1639    fn test_unit_quaternion_mul_quaternion() {
1640        // Test the multiplication of unit quaternions and quaternions
1641        assert_eq!(UQ32::J * Q32::K, Q32::new(0.0, 1.0, 0.0, 0.0));
1642    }
1643
1644    #[test]
1645    fn test_unit_quaternion_mul_underlying() {
1646        // Test the multiplication of unit quaternions and underlying types
1647        assert_eq!(UQ32::J * 2.0f32, Q32::new(0.0, 0.0, 2.0, 0.0));
1648    }
1649
1650    #[test]
1651    fn test_f32_mul_unit_quaternion() {
1652        // Test the multiplication of `f32` values and `f32` unit quaternions
1653        assert_eq!(3.0f32 * UQ32::K, Q32::new(0.0, 0.0, 0.0, 3.0));
1654    }
1655
1656    #[test]
1657    fn test_f64_mul_unit_quaternion() {
1658        // Test the multiplication of `f64` values and `f64` unit quaternions
1659        assert_eq!(4.0f64 * UQ64::I, Q64::new(0.0, 4.0, 0.0, 0.0));
1660    }
1661
1662    #[test]
1663    #[cfg(feature = "unstable")]
1664    fn test_unit_quaternion_mul_pure_quaternion() {
1665        // Test the multiplication of unit quaternions and pure quaternions
1666        assert_eq!(
1667            UQ32::J * PQ32::new(1.0, 2.0, 3.0),
1668            Q32::new(-2.0, 3.0, 0.0, -1.0)
1669        );
1670    }
1671
1672    #[test]
1673    fn test_unit_quaternion_div() {
1674        // Test the division of unit quaternions
1675        assert_eq!(UQ32::I / UQ32::J, -UQ32::K);
1676    }
1677
1678    #[test]
1679    fn test_unit_quaternion_div_quaternion() {
1680        // Test the division of unit quaternions and quaternions
1681        assert_eq!(UQ32::J / Q32::K, Q32::new(0.0, -1.0, 0.0, 0.0));
1682    }
1683
1684    #[test]
1685    fn test_unit_quaternion_div_underlying() {
1686        // Test the division of unit quaternions and underlying types
1687        assert_eq!(UQ32::J / 2.0f32, Q32::new(0.0, 0.0, 0.5, 0.0));
1688    }
1689
1690    #[test]
1691    fn test_f32_div_unit_quaternion() {
1692        // Test the division of `f32` values and `f32` unit quaternions
1693        assert_eq!(3.0f32 / UQ32::K, Q32::new(0.0, 0.0, 0.0, -3.0));
1694    }
1695
1696    #[test]
1697    fn test_f64_div_unit_quaternion() {
1698        // Test the division of `f64` values and `f64` unit quaternions
1699        assert_eq!(4.0f64 / UQ64::I, Q64::new(0.0, -4.0, 0.0, 0.0));
1700    }
1701
1702    #[test]
1703    #[cfg(feature = "unstable")]
1704    fn test_unit_quaternion_div_pure_quaternion() {
1705        // Test the division of unit quaternions and pure quaternions
1706        assert_eq!(
1707            UQ32::J / PQ32::new(1.0, 2.0, 3.0),
1708            Q32::new(2.0, -3.0, 0.0, 1.0) / 14.0
1709        );
1710    }
1711
1712    #[test]
1713    #[cfg(any(feature = "std", feature = "libm"))]
1714    #[allow(clippy::op_ref)]
1715    fn test_add_with_ref_unit_quaternion() {
1716        // Test the addition of unit quaternions with references
1717        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1718        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1719        assert_eq!(lhs + rhs, &lhs + rhs);
1720        assert_eq!(lhs + rhs, lhs + &rhs);
1721        assert_eq!(lhs + rhs, &lhs + &rhs);
1722    }
1723
1724    #[test]
1725    #[cfg(any(feature = "std", feature = "libm"))]
1726    #[allow(clippy::op_ref)]
1727    fn test_sub_with_ref_unit_quaternion() {
1728        // Test the subtraction of unit quaternions with references
1729        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1730        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1731        assert_eq!(lhs - rhs, &lhs - rhs);
1732        assert_eq!(lhs - rhs, lhs - &rhs);
1733        assert_eq!(lhs - rhs, &lhs - &rhs);
1734    }
1735
1736    #[test]
1737    #[cfg(any(feature = "std", feature = "libm"))]
1738    #[allow(clippy::op_ref)]
1739    fn test_mul_with_ref_unit_quaternion() {
1740        // Test the multiplication of unit quaternions with references
1741        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1742        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1743        assert_eq!(lhs * rhs, &lhs * rhs);
1744        assert_eq!(lhs * rhs, lhs * &rhs);
1745        assert_eq!(lhs * rhs, &lhs * &rhs);
1746    }
1747
1748    #[test]
1749    #[cfg(any(feature = "std", feature = "libm"))]
1750    #[allow(clippy::op_ref)]
1751    fn test_div_with_ref_unit_quaternion() {
1752        // Test the division of unit quaternions with references
1753        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1754        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1755        assert_eq!(lhs / rhs, &lhs / rhs);
1756        assert_eq!(lhs / rhs, lhs / &rhs);
1757        assert_eq!(lhs / rhs, &lhs / &rhs);
1758    }
1759
1760    #[test]
1761    #[cfg(any(feature = "std", feature = "libm"))]
1762    #[allow(clippy::op_ref)]
1763    fn test_add_quaternion_with_ref_unit_quaternion() {
1764        // Test the addition of unit quaternions and quaternions with references
1765        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1766        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1767        assert_eq!(lhs + rhs, &lhs + rhs);
1768        assert_eq!(lhs + rhs, lhs + &rhs);
1769        assert_eq!(lhs + rhs, &lhs + &rhs);
1770    }
1771
1772    #[test]
1773    #[cfg(any(feature = "std", feature = "libm"))]
1774    #[allow(clippy::op_ref)]
1775    fn test_sub_quaternion_with_ref_unit_quaternion() {
1776        // Test the subtraction of unit quaternions and quaternions with references
1777        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1778        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1779        assert_eq!(lhs - rhs, &lhs - rhs);
1780        assert_eq!(lhs - rhs, lhs - &rhs);
1781        assert_eq!(lhs - rhs, &lhs - &rhs);
1782    }
1783
1784    #[test]
1785    #[cfg(any(feature = "std", feature = "libm"))]
1786    #[allow(clippy::op_ref)]
1787    fn test_mul_quaternion_with_ref_unit_quaternion() {
1788        // Test the multiplication of unit quaternions and quaternions with references
1789        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1790        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1791        assert_eq!(lhs * rhs, &lhs * rhs);
1792        assert_eq!(lhs * rhs, lhs * &rhs);
1793        assert_eq!(lhs * rhs, &lhs * &rhs);
1794    }
1795
1796    #[test]
1797    #[cfg(any(feature = "std", feature = "libm"))]
1798    #[allow(clippy::op_ref)]
1799    fn test_div_quaternion_with_ref_unit_quaternion() {
1800        // Test the division of unit quaternions and quaternions with references
1801        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1802        let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1803        assert_eq!(lhs / rhs, &lhs / rhs);
1804        assert_eq!(lhs / rhs, lhs / &rhs);
1805        assert_eq!(lhs / rhs, &lhs / &rhs);
1806    }
1807
1808    #[test]
1809    #[cfg(any(feature = "std", feature = "libm"))]
1810    #[allow(clippy::op_ref)]
1811    fn test_add_real_with_ref_unit_quaternion() {
1812        // Test the addition of unit quaternions and real numbers with references
1813        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1814        let rhs = 5.0;
1815        assert_eq!(lhs + rhs, &lhs + rhs);
1816        assert_eq!(lhs + rhs, lhs + &rhs);
1817        assert_eq!(lhs + rhs, &lhs + &rhs);
1818    }
1819
1820    #[test]
1821    #[cfg(any(feature = "std", feature = "libm"))]
1822    #[allow(clippy::op_ref)]
1823    fn test_sub_real_with_ref_unit_quaternion() {
1824        // Test the subtraction of unit quaternions and real numbers with references
1825        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1826        let rhs = 5.0;
1827        assert_eq!(lhs - rhs, &lhs - rhs);
1828        assert_eq!(lhs - rhs, lhs - &rhs);
1829        assert_eq!(lhs - rhs, &lhs - &rhs);
1830    }
1831
1832    #[test]
1833    #[cfg(any(feature = "std", feature = "libm"))]
1834    #[allow(clippy::op_ref)]
1835    fn test_mul_real_with_ref_unit_quaternion() {
1836        // Test the multiplication of unit quaternions and real numbers with references
1837        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1838        let rhs = 5.0;
1839        assert_eq!(lhs * rhs, &lhs * rhs);
1840        assert_eq!(lhs * rhs, lhs * &rhs);
1841        assert_eq!(lhs * rhs, &lhs * &rhs);
1842    }
1843
1844    #[test]
1845    #[cfg(any(feature = "std", feature = "libm"))]
1846    #[allow(clippy::op_ref)]
1847    fn test_div_real_with_ref_unit_quaternion() {
1848        // Test the division of unit quaternions and real numbers with references
1849        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1850        let rhs = 5.0;
1851        assert_eq!(lhs / rhs, &lhs / rhs);
1852        assert_eq!(lhs / rhs, lhs / &rhs);
1853        assert_eq!(lhs / rhs, &lhs / &rhs);
1854    }
1855
1856    #[test]
1857    #[cfg(any(feature = "std", feature = "libm"))]
1858    #[cfg(feature = "unstable")]
1859    #[allow(clippy::op_ref)]
1860    fn test_add_pure_quaternion_with_ref_unit_quaternion() {
1861        // Test the addition of unit quaternions and pure quaternions with
1862        // references
1863        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1864        let rhs = PQ32::new(5.0, 6.0, 7.0);
1865        assert_eq!(lhs + rhs, &lhs + rhs);
1866        assert_eq!(lhs + rhs, lhs + &rhs);
1867        assert_eq!(lhs + rhs, &lhs + &rhs);
1868    }
1869
1870    #[test]
1871    #[cfg(any(feature = "std", feature = "libm"))]
1872    #[cfg(feature = "unstable")]
1873    #[allow(clippy::op_ref)]
1874    fn test_sub_pure_quaternion_with_ref_unit_quaternion() {
1875        // Test the subtraction of unit quaternions and pure quaternions with
1876        // references
1877        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1878        let rhs = PQ32::new(5.0, 6.0, 7.0);
1879        assert_eq!(lhs - rhs, &lhs - rhs);
1880        assert_eq!(lhs - rhs, lhs - &rhs);
1881        assert_eq!(lhs - rhs, &lhs - &rhs);
1882    }
1883
1884    #[test]
1885    #[cfg(any(feature = "std", feature = "libm"))]
1886    #[cfg(feature = "unstable")]
1887    #[allow(clippy::op_ref)]
1888    fn test_mul_pure_quaternion_with_ref_unit_quaternion() {
1889        // Test the multiplication of unit quaternions and pure quaternions with
1890        // references
1891        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1892        let rhs = PQ32::new(5.0, 6.0, 7.0);
1893        assert_eq!(lhs * rhs, &lhs * rhs);
1894        assert_eq!(lhs * rhs, lhs * &rhs);
1895        assert_eq!(lhs * rhs, &lhs * &rhs);
1896    }
1897
1898    #[test]
1899    #[cfg(any(feature = "std", feature = "libm"))]
1900    #[cfg(feature = "unstable")]
1901    #[allow(clippy::op_ref)]
1902    fn test_div_pure_quaternion_with_ref_unit_quaternion() {
1903        // Test the division of unit quaternions and pure quaternions with
1904        // references
1905        let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1906        let rhs = PQ32::new(5.0, 6.0, 7.0);
1907        assert_eq!(lhs / rhs, &lhs / rhs);
1908        assert_eq!(lhs / rhs, lhs / &rhs);
1909        assert_eq!(lhs / rhs, &lhs / &rhs);
1910    }
1911
1912    #[test]
1913    fn test_mul_assign_unit_quaternion() {
1914        // Test the multiplication assignment operator with unit quaternions
1915        let mut q = Q32::new(1.0, 2.0, 3.0, 4.0);
1916        q *= UQ32::I;
1917        assert_eq!(q, Quaternion::new(-2.0, 1.0, 4.0, -3.0));
1918    }
1919
1920    #[test]
1921    fn test_div_assign_unit_quaternion() {
1922        // Test the division assignment operator with unit quaternions
1923        let mut q = Q32::new(1.0, 2.0, 3.0, 4.0);
1924        q /= UQ32::I;
1925        assert_eq!(q, Quaternion::new(2.0, -1.0, -4.0, 3.0));
1926    }
1927
1928    #[test]
1929    #[cfg(feature = "unstable")]
1930    fn test_pure_quaternion_add() {
1931        // Test the addition of pure quaternions
1932        assert_eq!(
1933            PQ32::new(1.0, 2.0, 3.0) + PQ32::new(4.0, 5.0, 6.0),
1934            PQ32::new(5.0, 7.0, 9.0)
1935        );
1936    }
1937
1938    #[test]
1939    #[cfg(feature = "unstable")]
1940    fn test_pure_quaternion_add_quaternion() {
1941        // Test the addition of pure quaternions and quaternions
1942        assert_eq!(
1943            PQ32::new(1.0, 2.0, 3.0) + Q32::new(4.0, 5.0, 6.0, 7.0),
1944            Q32::new(4.0, 6.0, 8.0, 10.0)
1945        );
1946    }
1947
1948    #[test]
1949    #[cfg(feature = "unstable")]
1950    fn test_pure_quaternion_add_real() {
1951        // Test the addition of pure quaternions and real numbers
1952        assert_eq!(
1953            PQ32::new(1.0, 2.0, 3.0) + 4.0,
1954            Q32::new(4.0, 1.0, 2.0, 3.0)
1955        );
1956    }
1957
1958    #[test]
1959    #[cfg(feature = "unstable")]
1960    fn test_pure_quaternion_add_unit_quaternion() {
1961        // Test the addition of pure quaternions and unit quaternions
1962        assert_eq!(
1963            PQ32::new(1.0, 2.0, 3.0) + UQ32::I,
1964            Q32::new(0.0, 2.0, 2.0, 3.0)
1965        );
1966    }
1967
1968    #[test]
1969    #[cfg(feature = "unstable")]
1970    fn test_f32_add_pure_quaternion() {
1971        // Test the addition of `f32` values and pure quaternions
1972        assert_eq!(
1973            3.0f32 + PQ32::new(1.0, 2.0, 3.0),
1974            Q32::new(3.0, 1.0, 2.0, 3.0)
1975        );
1976    }
1977
1978    #[test]
1979    #[cfg(feature = "unstable")]
1980    fn test_f64_add_pure_quaternion() {
1981        // Test the addition of `f64` values and pure quaternions
1982        assert_eq!(
1983            4.0f64 + PQ64::new(1.0, 2.0, 3.0),
1984            Q64::new(4.0, 1.0, 2.0, 3.0)
1985        );
1986    }
1987
1988    #[test]
1989    #[cfg(feature = "unstable")]
1990    fn test_pure_quaternion_sub() {
1991        // Test the subtraction of pure quaternions
1992        assert_eq!(
1993            PQ32::new(1.0, 2.0, 3.0) - PQ32::new(4.0, 5.0, 6.0),
1994            PQ32::new(-3.0, -3.0, -3.0)
1995        );
1996    }
1997
1998    #[test]
1999    #[cfg(feature = "unstable")]
2000    fn test_pure_quaternion_sub_quaternion() {
2001        // Test the subtraction of pure quaternions and quaternions
2002        assert_eq!(
2003            PQ32::new(1.0, 2.0, 3.0) - Q32::new(4.0, 5.0, 6.0, 7.0),
2004            Q32::new(-4.0, -4.0, -4.0, -4.0)
2005        );
2006    }
2007
2008    #[test]
2009    #[cfg(feature = "unstable")]
2010    fn test_pure_quaternion_sub_real() {
2011        // Test the subtraction of pure quaternions and real numbers
2012        assert_eq!(
2013            PQ32::new(1.0, 2.0, 3.0) - 4.0,
2014            Q32::new(-4.0, 1.0, 2.0, 3.0)
2015        );
2016    }
2017
2018    #[test]
2019    #[cfg(feature = "unstable")]
2020    fn test_pure_quaternion_sub_unit_quaternion() {
2021        // Test the subtraction of pure quaternions and unit quaternions
2022        assert_eq!(
2023            PQ32::new(1.0, 2.0, 3.0) - UQ32::J,
2024            Q32::new(0.0, 1.0, 1.0, 3.0)
2025        );
2026    }
2027
2028    #[test]
2029    #[cfg(feature = "unstable")]
2030    fn test_f32_sub_pure_quaternion() {
2031        // Test the subtraction of `f32` values and pure quaternions
2032        assert_eq!(
2033            3.0f32 - PQ32::new(1.0, 2.0, 3.0),
2034            Q32::new(3.0, -1.0, -2.0, -3.0)
2035        );
2036    }
2037
2038    #[test]
2039    #[cfg(feature = "unstable")]
2040    fn test_f64_sub_pure_quaternion() {
2041        // Test the subtraction of `f64` values and pure quaternions
2042        assert_eq!(
2043            4.0f64 - PQ64::new(1.0, 2.0, 3.0),
2044            Q64::new(4.0, -1.0, -2.0, -3.0)
2045        );
2046    }
2047
2048    #[test]
2049    #[cfg(feature = "unstable")]
2050    fn test_pure_quaternion_mul() {
2051        // Test the multiplication of pure quaternions
2052        assert_eq!(
2053            PQ32::new(1.0, 2.0, 3.0) * PQ32::new(4.0, 5.0, 6.0),
2054            Q32::new(0.0, 1.0, 2.0, 3.0) * Q32::new(0.0, 4.0, 5.0, 6.0)
2055        );
2056    }
2057
2058    #[test]
2059    #[cfg(feature = "unstable")]
2060    fn test_pure_quaternion_mul_quaternion() {
2061        // Test the multiplication of pure quaternions and quaternions
2062        assert_eq!(
2063            PQ32::new(1.0, 2.0, 3.0) * Q32::new(4.0, 5.0, 6.0, 7.0),
2064            Q32::new(0.0, 1.0, 2.0, 3.0) * Q32::new(4.0, 5.0, 6.0, 7.0)
2065        );
2066    }
2067
2068    #[test]
2069    #[cfg(feature = "unstable")]
2070    fn test_pure_quaternion_mul_real() {
2071        // Test the multiplication of pure quaternions and real numbers
2072        assert_eq!(PQ32::new(1.0, 2.0, 3.0) * 4.0, PQ32::new(4.0, 8.0, 12.0));
2073    }
2074
2075    #[test]
2076    #[cfg(feature = "unstable")]
2077    fn test_pure_quaternion_mul_unit_quaternion() {
2078        // Test the multiplication of pure quaternions and unit quaternions
2079        assert_eq!(
2080            PQ32::new(1.0, 2.0, 3.0) * UQ32::I,
2081            Q32::new(0.0, 1.0, 2.0, 3.0) * Q32::new(0.0, 1.0, 0.0, 0.0)
2082        );
2083    }
2084
2085    #[test]
2086    #[cfg(feature = "unstable")]
2087    fn test_f32_mul_pure_quaternion() {
2088        // Test the multiplication of `f32` values and pure quaternions
2089        assert_eq!(3.0f32 * PQ32::new(1.0, 2.0, 3.0), PQ32::new(3.0, 6.0, 9.0));
2090    }
2091
2092    #[test]
2093    #[cfg(feature = "unstable")]
2094    fn test_f64_mul_pure_quaternion() {
2095        // Test the multiplication of `f64` values and pure quaternions
2096        assert_eq!(
2097            4.0f64 * PQ64::new(1.0, 2.0, 3.0),
2098            PQ64::new(4.0, 8.0, 12.0)
2099        );
2100    }
2101
2102    #[test]
2103    #[cfg(feature = "unstable")]
2104    fn test_pure_quaternion_div() {
2105        // Test the division of pure quaternions
2106        assert_eq!(
2107            PQ32::new(1.0, 2.0, 3.0) / PQ32::new(4.0, 5.0, 6.0),
2108            Q32::new(0.0, 1.0, 2.0, 3.0) / Q32::new(0.0, 4.0, 5.0, 6.0)
2109        );
2110    }
2111
2112    #[test]
2113    #[cfg(feature = "unstable")]
2114    fn test_pure_quaternion_div_quaternion() {
2115        // Test the division of pure quaternions and quaternions
2116        assert_eq!(
2117            PQ32::new(1.0, 2.0, 3.0) / Q32::new(4.0, 5.0, 6.0, 7.0),
2118            Q32::new(0.0, 1.0, 2.0, 3.0) / Q32::new(4.0, 5.0, 6.0, 7.0)
2119        );
2120    }
2121
2122    #[test]
2123    #[cfg(feature = "unstable")]
2124    fn test_pure_quaternion_div_real() {
2125        // Test the division of pure quaternions and real numbers
2126        assert_eq!(PQ32::new(1.0, 2.0, 3.0) / 4.0, PQ32::new(0.25, 0.5, 0.75));
2127    }
2128
2129    #[test]
2130    #[cfg(feature = "unstable")]
2131    fn test_pure_quaternion_div_unit_quaternion() {
2132        // Test the division of pure quaternions and unit quaternions
2133        assert_eq!(
2134            PQ32::new(1.0, 2.0, 3.0) / UQ32::I,
2135            Q32::new(0.0, 1.0, 2.0, 3.0) / Q32::new(0.0, 1.0, 0.0, 0.0)
2136        );
2137    }
2138
2139    #[test]
2140    #[cfg(feature = "unstable")]
2141    fn test_f32_div_pure_quaternion() {
2142        // Test the division of `f32` values and pure quaternions
2143        assert_eq!(
2144            4.0f32 / PQ32::new(1.0, 2.0, 3.0),
2145            PQ32::new(-4.0, -8.0, -12.0) / 14.0
2146        );
2147    }
2148
2149    #[test]
2150    #[cfg(feature = "unstable")]
2151    fn test_f64_div_pure_quaternion() {
2152        // Test the division of `f64` values and pure quaternions
2153        assert_eq!(
2154            4.0f64 / PQ64::new(1.0, 2.0, 3.0),
2155            PQ64::new(-4.0, -8.0, -12.0) / 14.0
2156        );
2157    }
2158
2159    #[test]
2160    #[cfg(feature = "unstable")]
2161    #[allow(clippy::op_ref)]
2162    fn test_pure_quaternion_add_ref() {
2163        // Test the addition of pure quaternions with references
2164        let lhs = PQ32::new(1.0, 2.0, 3.0);
2165        let rhs = PQ32::new(4.0, 5.0, 6.0);
2166        assert_eq!(lhs + rhs, &lhs + rhs);
2167        assert_eq!(lhs + rhs, lhs + &rhs);
2168        assert_eq!(lhs + rhs, &lhs + &rhs);
2169    }
2170
2171    #[test]
2172    #[cfg(feature = "unstable")]
2173    #[allow(clippy::op_ref)]
2174    fn test_pure_quaternion_sub_ref() {
2175        // Test the subtraction of pure quaternions with references
2176        let lhs = PQ32::new(1.0, 2.0, 3.0);
2177        let rhs = PQ32::new(4.0, 5.0, 6.0);
2178        assert_eq!(lhs - rhs, &lhs - rhs);
2179        assert_eq!(lhs - rhs, lhs - &rhs);
2180        assert_eq!(lhs - rhs, &lhs - &rhs);
2181    }
2182
2183    #[test]
2184    #[cfg(feature = "unstable")]
2185    #[allow(clippy::op_ref)]
2186    fn test_pure_quaternion_mul_ref() {
2187        // Test the multiplication of pure quaternions with references
2188        let lhs = PQ32::new(1.0, 2.0, 3.0);
2189        let rhs = PQ32::new(4.0, 5.0, 6.0);
2190        assert_eq!(lhs * rhs, &lhs * rhs);
2191        assert_eq!(lhs * rhs, lhs * &rhs);
2192        assert_eq!(lhs * rhs, &lhs * &rhs);
2193    }
2194
2195    #[test]
2196    #[cfg(feature = "unstable")]
2197    #[allow(clippy::op_ref)]
2198    fn test_pure_quaternion_div_ref() {
2199        // Test the division of pure quaternions with references
2200        let lhs = PQ32::new(1.0, 2.0, 3.0);
2201        let rhs = PQ32::new(4.0, 5.0, 6.0);
2202        assert_eq!(lhs / rhs, &lhs / rhs);
2203        assert_eq!(lhs / rhs, lhs / &rhs);
2204        assert_eq!(lhs / rhs, &lhs / &rhs);
2205    }
2206
2207    #[test]
2208    #[cfg(feature = "unstable")]
2209    #[allow(clippy::op_ref)]
2210    fn test_pure_quaternion_add_quaternion_ref() {
2211        // Test the addition of pure quaternions and quaternions with references
2212        let lhs = PQ32::new(1.0, 2.0, 3.0);
2213        let rhs = Q32::new(4.0, 5.0, 6.0, 7.0);
2214        assert_eq!(lhs + rhs, &lhs + rhs);
2215        assert_eq!(lhs + rhs, lhs + &rhs);
2216        assert_eq!(lhs + rhs, &lhs + &rhs);
2217    }
2218
2219    #[test]
2220    #[cfg(feature = "unstable")]
2221    #[allow(clippy::op_ref)]
2222    fn test_pure_quaternion_sub_quaternion_ref() {
2223        // Test the subtraction of pure quaternions and quaternions with references
2224        let lhs = PQ32::new(1.0, 2.0, 3.0);
2225        let rhs = Q32::new(4.0, 5.0, 6.0, 7.0);
2226        assert_eq!(lhs - rhs, &lhs - rhs);
2227        assert_eq!(lhs - rhs, lhs - &rhs);
2228        assert_eq!(lhs - rhs, &lhs - &rhs);
2229    }
2230
2231    #[test]
2232    #[cfg(feature = "unstable")]
2233    #[allow(clippy::op_ref)]
2234    fn test_pure_quaternion_mul_quaternion_ref() {
2235        // Test the multiplication of pure quaternions and quaternions with
2236        // references
2237        let lhs = PQ32::new(1.0, 2.0, 3.0);
2238        let rhs = Q32::new(4.0, 5.0, 6.0, 7.0);
2239        assert_eq!(lhs * rhs, &lhs * rhs);
2240        assert_eq!(lhs * rhs, lhs * &rhs);
2241        assert_eq!(lhs * rhs, &lhs * &rhs);
2242    }
2243
2244    #[test]
2245    #[cfg(feature = "unstable")]
2246    #[allow(clippy::op_ref)]
2247    fn test_pure_quaternion_div_quaternion_ref() {
2248        // Test the division of pure quaternions and quaternions with references
2249        let lhs = PQ32::new(1.0, 2.0, 3.0);
2250        let rhs = Q32::new(4.0, 5.0, 6.0, 7.0);
2251        assert_eq!(lhs / rhs, &lhs / rhs);
2252        assert_eq!(lhs / rhs, lhs / &rhs);
2253        assert_eq!(lhs / rhs, &lhs / &rhs);
2254    }
2255
2256    #[test]
2257    #[cfg(feature = "unstable")]
2258    #[allow(clippy::op_ref)]
2259    fn test_pure_quaternion_add_real_ref() {
2260        // Test the addition of pure quaternions and real numbers with references
2261        let lhs = PQ32::new(1.0, 2.0, 3.0);
2262        let rhs = 4.0;
2263        assert_eq!(lhs + rhs, &lhs + rhs);
2264        assert_eq!(lhs + rhs, lhs + &rhs);
2265        assert_eq!(lhs + rhs, &lhs + &rhs);
2266    }
2267
2268    #[test]
2269    #[cfg(feature = "unstable")]
2270    #[allow(clippy::op_ref)]
2271    fn test_pure_quaternion_sub_real_ref() {
2272        // Test the subtraction of pure quaternions and real numbers with
2273        // references
2274        let lhs = PQ32::new(1.0, 2.0, 3.0);
2275        let rhs = 4.0;
2276        assert_eq!(lhs - rhs, &lhs - rhs);
2277        assert_eq!(lhs - rhs, lhs - &rhs);
2278        assert_eq!(lhs - rhs, &lhs - &rhs);
2279    }
2280
2281    #[test]
2282    #[cfg(feature = "unstable")]
2283    #[allow(clippy::op_ref)]
2284    fn test_pure_quaternion_mul_real_ref() {
2285        // Test the multiplication of pure quaternions and real numbers with
2286        // references
2287        let lhs = PQ32::new(1.0, 2.0, 3.0);
2288        let rhs = 4.0;
2289        assert_eq!(lhs * rhs, &lhs * rhs);
2290        assert_eq!(lhs * rhs, lhs * &rhs);
2291        assert_eq!(lhs * rhs, &lhs * &rhs);
2292    }
2293
2294    #[test]
2295    #[cfg(feature = "unstable")]
2296    #[allow(clippy::op_ref)]
2297    fn test_pure_quaternion_div_real_ref() {
2298        // Test the division of pure quaternions and real numbers with references
2299        let lhs = PQ32::new(1.0, 2.0, 3.0);
2300        let rhs = 4.0;
2301        assert_eq!(lhs / rhs, &lhs / rhs);
2302        assert_eq!(lhs / rhs, lhs / &rhs);
2303        assert_eq!(lhs / rhs, &lhs / &rhs);
2304    }
2305
2306    #[test]
2307    #[cfg(feature = "unstable")]
2308    #[allow(clippy::op_ref)]
2309    fn test_pure_quaternion_add_unit_quaternion_ref() {
2310        // Test the addition of pure quaternions and unit quaternions with
2311        // references
2312        let lhs = PQ32::new(1.0, 2.0, 3.0);
2313        let rhs = UQ32::I;
2314        assert_eq!(lhs + rhs, &lhs + rhs);
2315        assert_eq!(lhs + rhs, lhs + &rhs);
2316        assert_eq!(lhs + rhs, &lhs + &rhs);
2317    }
2318
2319    #[test]
2320    #[cfg(feature = "unstable")]
2321    #[allow(clippy::op_ref)]
2322    fn test_pure_quaternion_sub_unit_quaternion_ref() {
2323        // Test the subtraction of pure quaternions and unit quaternions with
2324        // references
2325        let lhs = PQ32::new(1.0, 2.0, 3.0);
2326        let rhs = UQ32::I;
2327        assert_eq!(lhs - rhs, &lhs - rhs);
2328        assert_eq!(lhs - rhs, lhs - &rhs);
2329        assert_eq!(lhs - rhs, &lhs - &rhs);
2330    }
2331
2332    #[test]
2333    #[cfg(feature = "unstable")]
2334    #[allow(clippy::op_ref)]
2335    fn test_pure_quaternion_mul_unit_quaternion_ref() {
2336        // Test the multiplication of pure quaternions and unit quaternions with
2337        // references
2338        let lhs = PQ32::new(1.0, 2.0, 3.0);
2339        let rhs = UQ32::I;
2340        assert_eq!(lhs * rhs, &lhs * rhs);
2341        assert_eq!(lhs * rhs, lhs * &rhs);
2342        assert_eq!(lhs * rhs, &lhs * &rhs);
2343    }
2344    #[test]
2345    #[cfg(feature = "unstable")]
2346    #[allow(clippy::op_ref)]
2347    fn test_pure_quaternion_div_unit_quaternion_ref() {
2348        // Test the division of pure quaternions and unit quaternions with
2349        // references
2350        let lhs = PQ32::new(1.0, 2.0, 3.0);
2351        let rhs = UQ32::I;
2352        assert_eq!(lhs / rhs, &lhs / rhs);
2353        assert_eq!(lhs / rhs, lhs / &rhs);
2354        assert_eq!(lhs / rhs, &lhs / &rhs);
2355    }
2356
2357    #[test]
2358    #[cfg(feature = "unstable")]
2359    fn test_pure_quaternion_add_assign() {
2360        // Test the addition assignment operator with pure quaternions
2361        let mut q = PQ32::new(1.0, 2.0, 3.0);
2362        q += PQ32::new(4.0, 5.0, 6.0);
2363        assert_eq!(q, PQ32::new(5.0, 7.0, 9.0));
2364    }
2365
2366    #[test]
2367    #[cfg(feature = "unstable")]
2368    fn test_pure_quaternion_sub_assign() {
2369        // Test the subtraction assignment operator with pure quaternions
2370        let mut q = PQ32::new(1.0, 2.0, 3.0);
2371        q -= PQ32::new(4.0, 5.0, 6.0);
2372        assert_eq!(q, PQ32::new(-3.0, -3.0, -3.0));
2373    }
2374
2375    #[test]
2376    #[cfg(feature = "unstable")]
2377    fn test_pure_quaternion_mul_assign() {
2378        // Test the multiplication assignment operator with pure quaternions
2379        let mut q = PQ32::new(1.0, 2.0, 3.0);
2380        q *= 2.0f32;
2381        assert_eq!(q, PQ32::new(2.0, 4.0, 6.0));
2382    }
2383
2384    #[test]
2385    #[cfg(feature = "unstable")]
2386    fn test_pure_quaternion_div_assign() {
2387        // Test the division assignment operator with pure quaternions
2388        let mut q = PQ32::new(1.0, 2.0, 3.0);
2389        q /= 4.0f32;
2390        assert_eq!(q, PQ32::new(0.25, 0.5, 0.75));
2391    }
2392}