particular/compute_method/
math.rs

1pub(crate) use {
2    std::{
3        iter::Sum,
4        ops::{Add, AddAssign, BitAnd, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
5    },
6    wide::CmpNe,
7};
8
9pub use ultraviolet::{
10    f32x4, f32x8, f64x2, f64x4, DVec2, DVec2x2, DVec2x4, DVec3, DVec3x2, DVec3x4, DVec4, DVec4x2,
11    DVec4x4, Vec2, Vec2x4, Vec2x8, Vec3, Vec3x4, Vec3x8, Vec4, Vec4x4, Vec4x8,
12};
13
14/// Trait for array types.
15pub trait Array {
16    /// The type of the elements in the array.
17    type Item;
18}
19impl<I, const D: usize> Array for [I; D] {
20    type Item = I;
21}
22
23/// Trait for the identity element `zero`.
24pub trait Zero {
25    /// `zero` value of the type.
26    const ZERO: Self;
27}
28
29/// Trait for the identity element `one`.
30pub trait One {
31    /// `one` value of the type.
32    const ONE: Self;
33}
34
35/// Trait for the element `infinity`.
36pub trait Infinity {
37    /// `infinity` (∞) value of the type.
38    fn infinity() -> Self;
39}
40
41/// Trait for operations on floating-point numbers.
42pub trait FloatOps:
43    Sized
44    + Neg<Output = Self>
45    + Add<Output = Self>
46    + AddAssign
47    + Sub<Output = Self>
48    + SubAssign
49    + Mul<Output = Self>
50    + MulAssign
51    + Div<Output = Self>
52    + DivAssign
53{
54}
55impl<F> FloatOps for F where
56    F: Sized
57        + Neg<Output = Self>
58        + Add<Output = Self>
59        + AddAssign
60        + Sub<Output = Self>
61        + SubAssign
62        + Mul<Output = Self>
63        + MulAssign
64        + Div<Output = Self>
65        + DivAssign
66{
67}
68
69/// Trait for floating-point numbers.
70pub trait Float: One + Zero + Clone + Infinity + FloatOps + PartialEq {
71    /// Returns the reciprocal (inverse) of a float.
72    #[inline]
73    fn recip(self) -> Self {
74        Self::ONE / self
75    }
76
77    /// Returns the square root of a float.
78    fn sqrt(self) -> Self;
79
80    /// Returns the reciprocal (inverse) square root of a float.
81    #[inline]
82    fn rsqrt(self) -> Self {
83        self.recip().sqrt()
84    }
85
86    /// Returns the minimum between two floats.
87    fn min(self, rhs: Self) -> Self;
88
89    /// Returns the maximum between two floats.
90    fn max(self, rhs: Self) -> Self;
91
92    /// Returns the mean of two floats.
93    #[inline]
94    fn mean(self, rhs: Self) -> Self {
95        (self + rhs) / (Self::ONE + Self::ONE)
96    }
97}
98
99/// Trait for types that can be converted into an array.
100pub trait IntoArray: Into<Self::Array> {
101    /// The array the type can be converted into.
102    type Array: Array;
103}
104
105/// Trait for operations on vectors of floating-point numbers.
106pub trait FloatVectorOps<F>:
107    Sized
108    + IntoArray
109    + Sum<Self>
110    + Neg<Output = Self>
111    + Add<Output = Self>
112    + AddAssign
113    + Sub<Output = Self>
114    + SubAssign
115    + Mul<F, Output = Self>
116    + MulAssign<F>
117    + Div<F, Output = Self>
118    + DivAssign<F>
119{
120}
121impl<V, F> FloatVectorOps<F> for V where
122    V: Sized
123        + IntoArray
124        + Sum<Self>
125        + Neg<Output = Self>
126        + Add<Output = Self>
127        + AddAssign
128        + Sub<Output = Self>
129        + SubAssign
130        + Mul<F, Output = Self>
131        + MulAssign<F>
132        + Div<F, Output = Self>
133        + DivAssign<F>
134{
135}
136
137/// Trait for vectors of floating-point numbers.
138pub trait FloatVector: Zero + Clone + FloatVectorOps<Self::Float> {
139    /// Floating-point associated with the vector.
140    type Float;
141
142    /// Returns the norm squared of the vector.
143    #[doc(alias = "length_squared")]
144    #[doc(alias = "magnitude_squared")]
145    fn norm_squared(self) -> Self::Float;
146}
147
148/// Trait for SIMD objects and their creation.
149pub trait SIMD {
150    /// Element from which the SIMD value can be created.
151    type Element;
152
153    /// The type a lane is equivalent to.
154    type Lane;
155
156    /// Creates a SIMD value with all lanes set to the specified value.
157    fn splat(element: Self::Element) -> Self;
158
159    /// Creates a SIMD value with lanes set to the given values.
160    fn new_lane(lane: Self::Lane) -> Self;
161}
162
163/// Marker trait for [`SIMD::Element`]s.
164pub trait SIMDElement<const L: usize>: Sized {
165    /// The [`SIMD`] type that `Self` is an element of.
166    type SIMD: SIMD<Element = Self, Lane = [Self; L]>;
167}
168
169/// Trait to reduce the lanes of a SIMD vector.
170pub trait Reduce: SIMD {
171    /// Sums the lanes of a SIMD vector.
172    fn reduce_sum(self) -> Self::Element;
173}
174
175/// Trait for casting from one primitive to another.
176pub trait FromPrimitive<U> {
177    /// Converts to this primitive from the input primitive.
178    fn from(p: U) -> Self;
179}
180
181/// Trait for casting one primitive to another.
182pub trait AsPrimitive: Sized {
183    /// Converts this primitive into the input primitive.
184    #[inline]
185    fn as_<F: FromPrimitive<Self>>(self) -> F {
186        F::from(self)
187    }
188}
189impl<U> AsPrimitive for U {}
190
191macro_rules! impl_zero_value {
192    ($s: ty, $zero: expr) => {
193        impl Zero for $s {
194            const ZERO: Self = $zero;
195        }
196    };
197}
198
199macro_rules! impl_float_values {
200    ($s: ty, $zero: expr, $one: expr, $inf: expr) => {
201        impl_zero_value!($s, $zero);
202
203        impl One for $s {
204            const ONE: Self = $one;
205        }
206
207        impl Infinity for $s {
208            #[inline]
209            fn infinity() -> Self {
210                $inf
211            }
212        }
213    };
214}
215
216impl_float_values!(f32, 0.0, 1.0, Self::INFINITY);
217impl_float_values!(f32x4, Self::ZERO, Self::ONE, Self::splat(f32::INFINITY));
218impl_float_values!(f32x8, Self::ZERO, Self::ONE, Self::splat(f32::INFINITY));
219impl_float_values!(f64, 0.0, 1.0, Self::INFINITY);
220impl_float_values!(f64x2, Self::ZERO, Self::ONE, Self::splat(f64::INFINITY));
221impl_float_values!(f64x4, Self::ZERO, Self::ONE, Self::splat(f64::INFINITY));
222
223impl_zero_value!(Vec2, Self::broadcast(f32::ZERO));
224impl_zero_value!(Vec3, Self::broadcast(f32::ZERO));
225impl_zero_value!(Vec4, Self::broadcast(f32::ZERO));
226impl_zero_value!(DVec2, Self::broadcast(f64::ZERO));
227impl_zero_value!(DVec3, Self::broadcast(f64::ZERO));
228impl_zero_value!(DVec4, Self::broadcast(f64::ZERO));
229impl_zero_value!(Vec2x4, Self::broadcast(f32x4::ZERO));
230impl_zero_value!(Vec2x8, Self::broadcast(f32x8::ZERO));
231impl_zero_value!(Vec3x4, Self::broadcast(f32x4::ZERO));
232impl_zero_value!(Vec3x8, Self::broadcast(f32x8::ZERO));
233impl_zero_value!(Vec4x4, Self::broadcast(f32x4::ZERO));
234impl_zero_value!(Vec4x8, Self::broadcast(f32x8::ZERO));
235impl_zero_value!(DVec2x2, Self::broadcast(f64x2::ZERO));
236impl_zero_value!(DVec2x4, Self::broadcast(f64x4::ZERO));
237impl_zero_value!(DVec3x2, Self::broadcast(f64x2::ZERO));
238impl_zero_value!(DVec3x4, Self::broadcast(f64x4::ZERO));
239impl_zero_value!(DVec4x2, Self::broadcast(f64x2::ZERO));
240impl_zero_value!(DVec4x4, Self::broadcast(f64x4::ZERO));
241
242macro_rules! impl_float {
243    ($s: ty, $recip: expr, $recip_sqrt: expr) => {
244        #[allow(clippy::redundant_closure_call)]
245        impl Float for $s {
246            #[inline]
247            fn recip(self) -> Self {
248                $recip(self)
249            }
250
251            #[inline]
252            fn sqrt(self) -> Self {
253                self.sqrt()
254            }
255
256            #[inline]
257            fn rsqrt(self) -> Self {
258                $recip_sqrt(self)
259            }
260
261            #[inline]
262            fn min(self, rhs: Self) -> Self {
263                self.min(rhs)
264            }
265
266            #[inline]
267            fn max(self, rhs: Self) -> Self {
268                self.max(rhs)
269            }
270        }
271    };
272}
273
274impl_float!(f32, Self::recip, |f| Self::recip(f).sqrt());
275impl_float!(f32x4, Self::recip, Self::recip_sqrt);
276impl_float!(f32x8, Self::recip, Self::recip_sqrt);
277impl_float!(f64, Self::recip, |f| Self::recip(f).sqrt());
278impl_float!(f64x2, |f| 1.0 / f, |f| Self::recip(f).sqrt());
279impl_float!(f64x4, |f| 1.0 / f, |f| Self::recip(f).sqrt());
280
281macro_rules! impl_into_array {
282    ($vector: ty, [$float: ty; $dim: literal]) => {
283        impl IntoArray for $vector {
284            type Array = [$float; $dim];
285        }
286    };
287}
288
289impl_into_array!(Vec2, [f32; 2]);
290impl_into_array!(Vec3, [f32; 3]);
291impl_into_array!(Vec4, [f32; 4]);
292impl_into_array!(DVec2, [f64; 2]);
293impl_into_array!(DVec3, [f64; 3]);
294impl_into_array!(DVec4, [f64; 4]);
295impl_into_array!(Vec2x4, [f32x4; 2]);
296impl_into_array!(Vec2x8, [f32x8; 2]);
297impl_into_array!(Vec3x4, [f32x4; 3]);
298impl_into_array!(Vec3x8, [f32x8; 3]);
299impl_into_array!(Vec4x4, [f32x4; 4]);
300impl_into_array!(Vec4x8, [f32x8; 4]);
301impl_into_array!(DVec2x2, [f64x2; 2]);
302impl_into_array!(DVec2x4, [f64x4; 2]);
303impl_into_array!(DVec3x2, [f64x2; 3]);
304impl_into_array!(DVec3x4, [f64x4; 3]);
305impl_into_array!(DVec4x2, [f64x2; 4]);
306impl_into_array!(DVec4x4, [f64x4; 4]);
307
308macro_rules! impl_float_vector {
309    ($vector: ty, $float: ty) => {
310        impl FloatVector for $vector {
311            type Float = $float;
312
313            #[inline]
314            fn norm_squared(self) -> Self::Float {
315                self.mag_sq()
316            }
317        }
318    };
319}
320
321impl_float_vector!(Vec2, f32);
322impl_float_vector!(Vec3, f32);
323impl_float_vector!(Vec4, f32);
324impl_float_vector!(DVec2, f64);
325impl_float_vector!(DVec3, f64);
326impl_float_vector!(DVec4, f64);
327impl_float_vector!(Vec2x4, f32x4);
328impl_float_vector!(Vec2x8, f32x8);
329impl_float_vector!(Vec3x4, f32x4);
330impl_float_vector!(Vec3x8, f32x8);
331impl_float_vector!(Vec4x4, f32x4);
332impl_float_vector!(Vec4x8, f32x8);
333impl_float_vector!(DVec2x2, f64x2);
334impl_float_vector!(DVec2x4, f64x4);
335impl_float_vector!(DVec3x2, f64x2);
336impl_float_vector!(DVec3x4, f64x4);
337impl_float_vector!(DVec4x2, f64x2);
338impl_float_vector!(DVec4x4, f64x4);
339
340macro_rules! impl_simd {
341    ($simd: ty, $el: ty, $lane: literal, $splat: expr, $new_lane: expr) => {
342        #[allow(clippy::redundant_closure_call)]
343        impl SIMD for $simd {
344            type Element = $el;
345
346            type Lane = [Self::Element; $lane];
347
348            #[inline]
349            fn splat(element: Self::Element) -> Self {
350                $splat(element)
351            }
352
353            #[inline]
354            fn new_lane(lane: Self::Lane) -> Self {
355                $new_lane(lane)
356            }
357        }
358
359        impl SIMDElement<$lane> for $el {
360            type SIMD = $simd;
361        }
362    };
363}
364
365macro_rules! impl_simd_float {
366    ($simd: ty, [$el: ty; $lane: literal]) => {
367        impl_simd!($simd, $el, $lane, Self::splat, Self::from);
368    };
369}
370
371macro_rules! impl_simd_vector {
372    ($simd: ty, [$el: ty; $lane: literal]) => {
373        impl_simd!(
374            $simd,
375            $el,
376            $lane,
377            |e| Self::splat(<$el>::from(e)),
378            |l: Self::Lane| Self::from(l.map(<$el>::from))
379        );
380    };
381}
382
383impl_simd_float!(f32x4, [f32; 4]);
384impl_simd_float!(f32x8, [f32; 8]);
385impl_simd_float!(f64x2, [f64; 2]);
386impl_simd_float!(f64x4, [f64; 4]);
387
388impl_simd_vector!(Vec2x4, [Vec2; 4]);
389impl_simd_vector!(Vec2x8, [Vec2; 8]);
390impl_simd_vector!(Vec3x4, [Vec3; 4]);
391impl_simd_vector!(Vec3x8, [Vec3; 8]);
392impl_simd_vector!(Vec4x4, [Vec4; 4]);
393impl_simd_vector!(Vec4x8, [Vec4; 8]);
394impl_simd_vector!(DVec2x2, [DVec2; 2]);
395impl_simd_vector!(DVec2x4, [DVec2; 4]);
396impl_simd_vector!(DVec3x2, [DVec3; 2]);
397impl_simd_vector!(DVec3x4, [DVec3; 4]);
398impl_simd_vector!(DVec4x2, [DVec4; 2]);
399impl_simd_vector!(DVec4x4, [DVec4; 4]);
400
401macro_rules! impl_reduce {
402    ($vector: ty, [$($f: ident),+]) => {
403        impl Reduce for $vector {
404            #[inline]
405            fn reduce_sum(self) -> Self::Element {
406                Self::Element {
407                    $($f: self.$f.reduce_add()),+
408                }
409            }
410        }
411    };
412}
413
414impl_reduce!(Vec2x4, [x, y]);
415impl_reduce!(Vec2x8, [x, y]);
416impl_reduce!(Vec3x4, [x, y, z]);
417impl_reduce!(Vec3x8, [x, y, z]);
418impl_reduce!(Vec4x4, [x, y, z, w]);
419impl_reduce!(Vec4x8, [x, y, z, w]);
420impl_reduce!(DVec2x2, [x, y]);
421impl_reduce!(DVec2x4, [x, y]);
422impl_reduce!(DVec3x2, [x, y, z]);
423impl_reduce!(DVec3x4, [x, y, z]);
424impl_reduce!(DVec4x2, [x, y, z, w]);
425impl_reduce!(DVec4x4, [x, y, z, w]);
426
427macro_rules! impl_from_primitive {
428    ($p1: ty => ($($pn: ty),*)) => {$(
429        impl FromPrimitive<$pn> for $p1 {
430            #[inline]
431            fn from(p: $pn) -> Self {
432                p as Self
433            }
434        }
435    )*};
436}
437
438impl_from_primitive!(f32 => (usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f64));
439impl_from_primitive!(f64 => (usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32));