Skip to main content

naga_rust_rt/
vector.rs

1use core::{cmp, fmt, ops};
2use num_traits::ConstZero;
3
4// Provides float math functions without std.
5// TODO: Be more rigorous and explicitly call libm depending on the feature flag
6// instead of using the trait.
7#[cfg(not(feature = "std"))]
8#[cfg_attr(test, allow(unused_imports))]
9use num_traits::float::Float as _;
10
11// -------------------------------------------------------------------------------------------------
12// Vector type declarations.
13//
14// Note that these vectors are *not* prepared to become implemented as SIMD vectors.
15// This is because, when SIMD happens, our SIMD story is going to be making the
16// application-level vectors’ *components* into SIMD vectors, like:
17//     Vec2<std::simd::Simd<f32, 4>>
18// This will allow us to have a constant SIMD lane count across the entire execution, even while
19// the shader code works with vectors of all sizes and scalars.
20
21/// This type wraps an underlying Rust-native scalar (or someday SIMD) type
22/// to provide *only* methods and operators which are compatible with shader
23/// function behaviors. That is, they act like `Vec*` even where `T` might not.
24/// This allows the code generator to not worry as much about mismatches
25/// between Rust and shader semantics.
26#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
27#[repr(transparent)]
28pub struct Scalar<T>(pub T);
29
30#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
31#[repr(C)]
32pub struct Vec2<T> {
33    pub x: T,
34    pub y: T,
35}
36
37#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
38#[repr(C)]
39pub struct Vec3<T> {
40    pub x: T,
41    pub y: T,
42    pub z: T,
43}
44
45#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
46#[repr(C)]
47pub struct Vec4<T> {
48    pub x: T,
49    pub y: T,
50    pub z: T,
51    pub w: T,
52}
53
54// -------------------------------------------------------------------------------------------------
55// Most general helper macros
56
57macro_rules! delegate_unary_method_elementwise {
58    (const $name:ident ($($component:tt)*)) => {
59        #[inline]
60        pub const fn $name(self) -> Self {
61            Self { $( $component: self.$component.$name() ),* }
62        }
63    };
64    ($name:ident ($($component:tt)*)) => {
65        #[inline]
66        pub fn $name(self) -> Self {
67            Self { $( $component: self.$component.$name() ),* }
68        }
69    };
70}
71
72macro_rules! delegate_unary_methods_elementwise {
73    (const { $($name:ident),* } $components:tt) => {
74        $( delegate_unary_method_elementwise!(const $name $components ); )*
75    };
76    ({ $($name:ident),* } $components:tt) => {
77        $( delegate_unary_method_elementwise!($name $components ); )*
78    };
79}
80
81macro_rules! delegate_binary_method_elementwise {
82    (const $name:ident ($($component:tt)*)) => {
83        #[inline]
84        pub const fn $name(self, rhs: Self) -> Self {
85            Self { $( $component: self.$component.$name(rhs.$component) ),* }
86        }
87    };
88    ($name:ident ($($component:tt)*)) => {
89        #[inline]
90        pub fn $name(self, rhs: Self) -> Self {
91            Self { $( $component: self.$component.$name(rhs.$component) ),* }
92        }
93    };
94}
95
96macro_rules! delegate_binary_methods_elementwise {
97    (const { $($name:ident),* } $components:tt) => {
98        $( delegate_binary_method_elementwise!(const $name $components ); )*
99    };
100    ({ $($name:ident),* } $components:tt) => {
101        $( delegate_binary_method_elementwise!($name $components ); )*
102    };
103}
104
105// -------------------------------------------------------------------------------------------------
106// Vector operations
107
108/// Generate arithmetic operators and functions for cases where the element type is a
109/// Rust primitive *integer*. (In these cases we must ask for wrapping operations.)
110///
111/// Note that this macro provides binary operation impls for `vec op vec` and `scalar op scalar`
112/// (considering a scalar as a 1-element vector) but not `scalar op vec` or `vec op scalar`.
113macro_rules! impl_vector_integer_arithmetic {
114    ($vec:ident, $int:ty, $( $component:tt )*) => {
115        impl ops::Add for $vec<$int> {
116            type Output = Self;
117            /// Wrapping addition.
118            #[inline]
119            fn add(self, rhs: Self) -> Self::Output {
120                $vec { $( $component: self.$component.wrapping_add(rhs.$component), )* }
121            }
122        }
123        impl ops::Sub for $vec<$int> {
124            type Output = Self;
125            /// Wrapping subtraction.
126            #[inline]
127            fn sub(self, rhs: Self) -> Self::Output {
128                $vec { $( $component: self.$component.wrapping_sub(rhs.$component), )* }
129            }
130        }
131        impl ops::Neg for $vec<$int> {
132            type Output = Self;
133            #[inline]
134            fn neg(self) -> Self::Output {
135                $vec { $( $component: self.$component.wrapping_neg(), )* }
136            }
137        }
138        impl ops::Mul for $vec<$int> {
139            type Output = Self;
140            /// Wrapping multiplication.
141            #[inline]
142            fn mul(self, rhs: Self) -> Self::Output {
143                $vec { $( $component: self.$component.wrapping_mul(rhs.$component), )* }
144            }
145        }
146        impl ops::Div for $vec<$int> {
147            type Output = Self;
148            /// On division by zero or overflow, returns the component of `self`,
149            /// per [WGSL](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#arithmetic-expr).
150            #[inline]
151            fn div(self, rhs: Self) -> Self::Output {
152                // wrapping_div() panics on division by zero, which is not what we need
153                $vec { $(
154                    $component:
155                        self.$component.checked_div(rhs.$component)
156                            .unwrap_or(self.$component),
157                )* }
158            }
159        }
160        impl ops::Rem for $vec<$int> {
161            type Output = Self;
162            #[inline]
163            fn rem(self, rhs: Self) -> Self::Output {
164                $vec { $( $component: self.$component.wrapping_rem(rhs.$component), )* }
165            }
166        }
167
168        impl $vec<$int> {
169            /// As per WGSL [`clamp()`](https://www.w3.org/TR/2026/CRD-WGSL-20260310/#clamp).
170            #[inline]
171            pub fn clamp(self, low: Self, high: Self) -> Self {
172                // std clamp() panics if low > high, which isn’t conformant
173                $vec { $( $component: self.$component.max(low.$component).min(high.$component) ),*  }
174            }
175
176            delegate_binary_methods_elementwise!({
177                max, min
178            } ($($component)*));
179        }
180    }
181}
182
183/// As impl_vector_integer_arithmetic! but for vector-scalar ops (not vector-vector or
184/// scalar-scalar).
185macro_rules! impl_vector_scalar_integer_arithmetic {
186    ($vec:ident, $int:ty, $( $component:tt )*) => {
187        impl ops::Add<Scalar<$int>> for $vec<$int> {
188            type Output = Self;
189            /// Wrapping addition.
190            #[inline]
191            fn add(self, Scalar(rhs): Scalar<$int>) -> Self::Output {
192                $vec { $( $component: self.$component.wrapping_add(rhs), )* }
193            }
194        }
195        impl ops::Sub<Scalar<$int>> for $vec<$int> {
196            type Output = Self;
197            /// Wrapping subtraction.
198            #[inline]
199            fn sub(self, Scalar(rhs): Scalar<$int>) -> Self::Output {
200                $vec { $( $component: self.$component.wrapping_sub(rhs), )* }
201            }
202        }
203        // Subtraction is non-commutative so we need a dedicated scalar-vector impl
204        impl ops::Sub<$vec<$int>> for Scalar<$int> {
205            type Output = $vec<$int>;
206            #[inline]
207            fn sub(self, rhs: $vec<$int>) -> Self::Output {
208                $vec { $( $component: self.0.wrapping_sub(rhs.$component), )* }
209            }
210        }
211        impl ops::Mul<Scalar<$int>> for $vec<$int> {
212            type Output = Self;
213            /// Wrapping multiplication.
214            #[inline]
215            fn mul(self, Scalar(rhs): Scalar<$int>) -> Self::Output {
216                $vec { $( $component: self.$component.wrapping_mul(rhs), )* }
217            }
218        }
219        impl ops::Div<Scalar<$int>> for $vec<$int> {
220            type Output = Self;
221            #[inline]
222            /// On division by zero or overflow, returns `self`,
223            /// per [WGSL](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#arithmetic-expr).
224            fn div(self, Scalar(rhs): Scalar<$int>) -> Self::Output {
225                // wrapping_div() panics on division by zero, which is not what we need
226                $vec { $(
227                    $component:
228                        self.$component.checked_div(rhs)
229                            .unwrap_or(self.$component),
230                )* }
231            }
232        }
233        impl ops::Div<$vec<$int>> for Scalar<$int> {
234            type Output = $vec<$int>;
235            #[inline]
236            fn div(self, rhs: $vec<$int>) -> Self::Output {
237                // wrapping_div() panics on division by zero, which is not what we need
238                $vec { $(
239                    $component:
240                        self.0.checked_div(rhs.$component)
241                            .unwrap_or(self.0),
242                )* }
243            }
244        }
245        impl ops::Rem<Scalar<$int>> for $vec<$int> {
246            type Output = Self;
247            #[inline]
248            fn rem(self, Scalar(rhs): Scalar<$int>) -> Self::Output {
249                $vec { $( $component: self.$component.wrapping_rem(rhs), )* }
250            }
251        }
252    }
253}
254
255/// Generate arithmetic operators and functions for cases where the element type is a
256/// Rust primitive *float*.
257macro_rules! impl_vector_float_arithmetic {
258    ($vec:ident, $float:ty, $( $component:tt )*) => {
259        // Vector-vector operations
260        impl ops::Add for $vec<$float> {
261            type Output = Self;
262            #[inline]
263            fn add(self, rhs: Self) -> Self::Output {
264                $vec { $( $component: self.$component + rhs.$component, )* }
265            }
266        }
267        impl ops::Sub for $vec<$float> {
268            type Output = Self;
269            #[inline]
270            fn sub(self, rhs: Self) -> Self::Output {
271                $vec { $( $component: self.$component - rhs.$component, )* }
272            }
273        }
274        impl ops::Neg for $vec<$float> {
275            type Output = Self;
276            #[inline]
277            fn neg(self) -> Self::Output {
278                $vec { $( $component: -self.$component, )* }
279            }
280        }
281        impl ops::Mul for $vec<$float> {
282            type Output = Self;
283            #[inline]
284            fn mul(self, rhs: Self) -> Self::Output {
285                $vec { $( $component: self.$component * rhs.$component, )* }
286            }
287        }
288        impl ops::Div for $vec<$float> {
289            type Output = Self;
290            #[inline]
291            fn div(self, rhs: Self) -> Self::Output {
292                $vec { $( $component: self.$component / rhs.$component, )* }
293            }
294        }
295        impl ops::Rem for $vec<$float> {
296            type Output = Self;
297            #[inline]
298            fn rem(self, rhs: Self) -> Self::Output {
299                $vec { $( $component: self.$component % rhs.$component, )* }
300            }
301        }
302
303        // Float math functions (mostly elementwise, but not exclusively)
304        impl $vec<$float> {
305            /// As per WGSL [`clamp()`](https://www.w3.org/TR/2026/CRD-WGSL-20260310/#clamp).
306            #[inline]
307            pub const fn clamp(self, low: Self, high: Self) -> Self {
308                // std clamp() panics if low > high, which isn’t conformant
309                $vec { $( $component: self.$component.max(low.$component).min(high.$component) ),*  }
310            }
311            /// As per WGSL [`distance()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#distance-builtin).
312            #[inline]
313            pub fn distance(self, rhs: Self) -> Scalar<$float> {
314                (self - rhs).length()
315            }
316            /// As per WGSL [`faceForward()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#faceForward-builtin).
317            #[inline]
318            pub fn face_forward(self, e2: Self, e3: Self) -> Self {
319                // note this is Rust's definition of signum which has no zero
320                self * Scalar((-e2.dot(e3)).0.signum())
321            }
322            /// As per WGSL [`length()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#length-builtin).
323            #[inline]
324            pub fn length(self) -> Scalar<$float> {
325                Scalar(self.dot(self).0.sqrt())
326            }
327            /// As per WGSL [`mix()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#mix-builtin).
328            #[inline]
329            pub const fn mix(self, rhs: Self, blend: Scalar<$float>) -> Self {
330                $vec { $( $component: self.$component * (1.0 - blend.0) + rhs.$component * blend.0 ),*  }
331            }
332            /// As per WGSL [`fma()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#fma-builtin).
333            #[inline]
334            pub fn mul_add(self, b: Self, c: Self) -> Self {
335                $vec { $( $component: self.$component.mul_add(b.$component, c.$component) ),*  }
336            }
337            /// As per WGSL [`normalize()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#normalize-builtin).
338            #[inline]
339            pub fn normalize(self) -> Self {
340                self / self.length()
341            }
342            /// As per WGSL [`reflect()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#reflect-builtin).
343            #[inline]
344            pub fn reflect(self, rhs: Self) -> Self {
345                self - rhs * (Scalar(2.0) * rhs.dot(self))
346            }
347            /// As per WGSL [`saturate()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#saturate-float-builtin).
348            #[inline]
349            pub const fn saturate(self) -> Self {
350                $vec { $( $component: self.$component.clamp(0.0, 1.0) ),* }
351            }
352            /// As per WGSL [`sign()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#sign-builtin).
353            #[inline]
354            pub const fn sign(self) -> Self {
355                $vec { $(
356                    // TODO: branchless form of this?
357                    $component: if self.$component == 0.0 {
358                        0.0
359                    } else {
360                        self.$component.signum()
361                    }
362                ),* }
363            }
364            /// As per WGSL [`smoothstep()`](https://www.w3.org/TR/2026/CRD-WGSL-20260310/#smoothstep-builtin),
365            /// but the third parameter called `x` is moved to be the `self` parameter.
366            pub fn smoothstep(self, edge0: Self, edge1: Self) -> Self {
367                let t = ((self - edge0) / (edge1 - edge0)).saturate();
368                t * t * (Scalar(3.0) - Scalar(2.0) * t)
369            }
370
371            // TODO: some more of these can be const
372            delegate_unary_methods_elementwise!(const {
373                abs
374            } ($($component)*));
375            delegate_unary_methods_elementwise!({
376                acos, acosh, asin, asinh, atan, atanh, ceil, cos, cosh, exp, exp2, floor, fract, log2, round,
377                sin, sinh, tan, tanh, trunc, to_degrees, to_radians
378            } ($($component)*));
379            delegate_binary_methods_elementwise!({
380                atan2, max, min, powf
381            } ($($component)*));
382
383            // TODO: modf, frexp, ldexp, cross, refract, step, smoothstep, inverse_sqrt,
384            // quantizeToF16, pack*,
385        }
386    }
387}
388
389/// As impl_vector_float_arithmetic! but for vector-scalar ops (not vector-vector or
390/// scalar-scalar).
391macro_rules! impl_vector_scalar_float_arithmetic {
392    ($vec:ident, $float:ty, $( $component:tt )*) => {
393        impl ops::Add<Scalar<$float>> for $vec<$float> {
394            type Output = $vec<$float>;
395            #[inline]
396            fn add(self, rhs: Scalar<$float>) -> Self::Output {
397                $vec { $( $component: self.$component + rhs.0, )* }
398            }
399        }
400        impl ops::Sub<Scalar<$float>> for $vec<$float> {
401            type Output = $vec<$float>;
402            #[inline]
403            fn sub(self, rhs: Scalar<$float>) -> Self::Output {
404                $vec { $( $component: self.$component - rhs.0, )* }
405            }
406        }
407        impl ops::Sub<$vec<$float>> for Scalar<$float> {
408            type Output = $vec<$float>;
409            #[inline]
410            fn sub(self, rhs: $vec<$float>) -> Self::Output {
411                $vec { $( $component: self.0 - rhs.$component, )* }
412            }
413        }
414        impl ops::Mul<Scalar<$float>> for $vec<$float> {
415            type Output = $vec<$float>;
416            #[inline]
417            fn mul(self, rhs: Scalar<$float>) -> Self::Output {
418                $vec { $( $component: self.$component * rhs.0, )* }
419            }
420        }
421        impl ops::Div<Scalar<$float>> for $vec<$float> {
422            type Output = $vec<$float>;
423            #[inline]
424            fn div(self, rhs: Scalar<$float>) -> Self::Output {
425                $vec { $( $component: self.$component / rhs.0, )* }
426            }
427        }
428        impl ops::Div<$vec<$float>> for Scalar<$float> {
429            type Output = $vec<$float>;
430            #[inline]
431            fn div(self, rhs: $vec<$float>) -> Self::Output {
432                $vec { $( $component: self.0 / rhs.$component, )* }
433            }
434        }
435        impl ops::Rem<Scalar<$float>> for $vec<$float> {
436            type Output = $vec<$float>;
437            #[inline]
438            fn rem(self, rhs: Scalar<$float>) -> Self::Output {
439                $vec { $( $component: self.$component % rhs.0, )* }
440            }
441        }
442    }
443}
444
445/// Bitwise impls for vectors of integers and vectors of bools
446macro_rules! impl_vector_bitwise_with_bool {
447    ($vec:ident, $int:ty, $( $component:tt )*) => {
448        impl ops::BitAnd for $vec<$int> {
449            type Output = Self;
450            fn bitand(self, rhs: Self) -> Self::Output {
451                $vec { $( $component: self.$component & rhs.$component, )* }
452            }
453        }
454        impl ops::BitOr for $vec<$int> {
455            type Output = Self;
456            fn bitor(self, rhs: Self) -> Self::Output {
457                $vec { $( $component: self.$component | rhs.$component, )* }
458            }
459        }
460        impl ops::BitXor for $vec<$int> {
461            type Output = Self;
462            fn bitxor(self, rhs: Self) -> Self::Output {
463                $vec { $( $component: self.$component ^ rhs.$component, )* }
464            }
465        }
466        impl ops::Not for $vec<$int> {
467            type Output = Self;
468            fn not(self) -> Self::Output {
469                $vec { $( $component: !self.$component, )* }
470            }
471        }
472    }
473}
474
475/// Bitwise impls for vectors of integers, not bools
476macro_rules! impl_vector_bitwise_without_bool {
477    ($vec:ident, $int:ty, $( $component:tt )*) => {
478        impl_vector_bitwise_with_bool!($vec, $int, $($component)*);
479
480        impl ops::Shl<$vec<u32>> for $vec<$int> {
481            type Output = Self;
482            fn shl(self, rhs: $vec<u32>) -> Self::Output {
483                $vec { $( $component: self.$component.unbounded_shl(rhs.$component), )* }
484            }
485        }
486        impl ops::Shr<$vec<u32>> for $vec<$int> {
487            type Output = Self;
488            fn shr(self, rhs: $vec<u32>) -> Self::Output {
489                $vec { $( $component: self.$component.unbounded_shr(rhs.$component), )* }
490            }
491        }
492
493    }
494}
495
496macro_rules! impl_element_casts {
497    ($ty:ident) => {
498        impl_element_casts!($ty, []);
499    };
500    ($ty:ident, [$($extra:tt)*]) => {
501        // TODO: These do not have the right cast semantics, but what *are* the right cast
502        // semantics? Naga IR docs are cryptic for `Expression::As`.
503        pub fn cast_elem_as_u32(self) -> $ty<u32> {
504            self.map(|component| component $($extra)* as u32)
505        }
506        pub fn cast_elem_as_i32(self) -> $ty<i32> {
507            self.map(|component| component $($extra)* as i32)
508        }
509        pub fn cast_elem_as_f32(self) -> $ty<f32> {
510            self.map(|component| component $($extra)* as f32)
511        }
512        pub fn cast_elem_as_f64(self) -> $ty<f64> {
513            self.map(|component| component $($extra)* as f64)
514        }
515    };
516}
517
518/// Implement `Index` and `IndexMut`.
519macro_rules! impl_index {
520    ($component_count:literal, $vector_type:ident, $index_type:ty) => {
521        impl<T> ops::Index<$index_type> for $vector_type<T> {
522            type Output = Scalar<T>;
523
524            #[inline]
525            fn index(&self, index: $index_type) -> &Self::Output {
526                // manual bounds check because we need to convert to usize and we’d like to have
527                // only one panic branch rather than two
528                if (0..$component_count).contains(&index) {
529                    &self.as_array_ref()[index as usize]
530                } else {
531                    panic!("matrix indexing out of bounds")
532                }
533            }
534        }
535
536        impl<T> ops::IndexMut<$index_type> for $vector_type<T> {
537            #[inline]
538            fn index_mut(&mut self, index: $index_type) -> &mut Self::Output {
539                if (0..$component_count).contains(&index) {
540                    &mut self.as_array_mut()[index as usize]
541                } else {
542                    panic!("vector indexing out of bounds")
543                }
544            }
545        }
546    };
547}
548
549macro_rules! impl_vector_regular_fns {
550    ( $ty:ident $component_count:literal : $( $component:tt )* ) => {
551        impl<T> $ty<T> {
552            pub fn splat(value: T) -> Self
553            where
554                T: Copy
555            {
556                Self { $( $component: value, )* }
557            }
558            pub fn splat_from_scalar(value: Scalar<T>) -> Self
559            where
560                T: Copy
561            {
562                Self { $( $component: value.0, )* }
563            }
564
565            /// Replaces the elements of `self` with the elements of `trues` wherever
566            /// `mask` contains [`true`].
567            pub const fn select(self, trues: Self, mask: $ty<bool>) -> Self
568            where
569                T: Copy
570            {
571                Self {
572                    $(
573                        $component: if mask.$component {
574                            trues.$component
575                        } else {
576                            self.$component
577                        },
578                    )*
579                }
580            }
581
582            pub fn map<U, F>(self, mut f: F) -> $ty<U>
583            where
584                F: FnMut(T) -> U,
585            {
586                $ty {
587                    $(
588                        $component: f(self.$component),
589                    )*
590                }
591            }
592
593            paste::paste! {
594                $(
595                    pub fn [< set_ $component >](&mut self, value: Scalar<T>) {
596                        self.$component = value.0;
597                    }
598                )*
599            }
600
601            #[inline]
602            fn as_array_ref(&self) -> &[Scalar<T>; $component_count] {
603                // Reinterpret the reference to self as a reference to an array.
604                // SAFETY: Vectors are `repr(C)` and have the same elements as the array.
605                unsafe { &*(&raw const *self).cast::<[Scalar<T>; $component_count]>() }
606            }
607            #[inline]
608            fn as_array_mut(&mut self) -> &mut [Scalar<T>; $component_count] {
609                // Reinterpret the reference to self as a reference to an array.
610                // SAFETY: Vectors are `repr(C)` and have the same elements as the array.
611                unsafe { &mut *(&raw mut *self).cast::<[Scalar<T>; $component_count]>() }
612            }
613
614            /// As per WGSL [`dot()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#dot-builtin).
615            //---
616            // Design note: this is generic so that it can be used by generic matrix operations
617            #[inline]
618            pub fn dot(self, rhs: Self) -> Scalar<T>
619            where
620                // TODO: the ConstZero is purely an artifact of the macro repetition
621                Scalar<T>: ops::Mul<Output = Scalar<T>> + num_traits::ConstZero,
622            {
623                $( Scalar(self.$component) * Scalar(rhs.$component) + )* Scalar::<T>::ZERO
624            }
625
626        }
627
628        impl_vector_integer_arithmetic!($ty, i32, $($component)*);
629        impl_vector_integer_arithmetic!($ty, u32, $($component)*);
630        impl_vector_float_arithmetic!($ty, f32, $($component)*);
631        impl_vector_float_arithmetic!($ty, f64, $($component)*);
632
633        impl_vector_bitwise_with_bool!($ty, bool, $($component)*);
634        impl_vector_bitwise_without_bool!($ty, i32, $($component)*);
635        impl_vector_bitwise_without_bool!($ty, u32, $($component)*);
636
637        impl $ty<i32> {
638            impl_element_casts!($ty);
639        }
640        impl $ty<u32> {
641            impl_element_casts!($ty);
642        }
643        impl $ty<f32> {
644            impl_element_casts!($ty);
645        }
646        impl $ty<f64> {
647            impl_element_casts!($ty);
648        }
649        impl $ty<bool> {
650            impl_element_casts!($ty, [as u8]);
651        }
652
653        // Indexing, by usize, i32, or u32, yields a scalar
654        impl_index!($component_count, $ty, usize);
655        impl_index!($component_count, $ty, i32);
656        impl_index!($component_count, $ty, u32);
657
658        // Zero constant and traits.
659        impl<T: ConstZero> $ty<T> {
660            // inherent so that traits are not needed in scope
661            pub const ZERO: Self = Self { $( $component: T::ZERO, )* };
662        }
663        impl<T: ConstZero> ConstZero for $ty<T>
664        where
665            Self: ops::Add<Output = Self>
666        {
667            const ZERO: Self = Self { $( $component: T::ZERO, )* };
668        }
669        impl<T: ConstZero> num_traits::Zero for $ty<T>
670        where
671            Self: ops::Add<Output = Self>
672        {
673            fn zero() -> Self {
674                Self::ZERO
675            }
676            fn is_zero(&self) -> bool {
677                $(T::is_zero(&self.$component) & )* true
678            }
679        }
680
681        // Elementwise comparison
682        impl<T: PartialOrd> $ty<T> {
683            pub fn elementwise_eq(self, rhs: Self) -> $ty<bool> {
684                self.partial_cmp(rhs).map(|cmp| matches!(cmp, Some(cmp::Ordering::Equal)))
685            }
686            pub fn elementwise_ne(self, rhs: Self) -> $ty<bool> {
687                self.partial_cmp(rhs).map(|cmp| !matches!(cmp, Some(cmp::Ordering::Equal)))
688            }
689            pub fn elementwise_lt(self, rhs: Self) -> $ty<bool> {
690                self.partial_cmp(rhs).map(|cmp| matches!(cmp, Some(cmp::Ordering::Less)))
691            }
692            pub fn elementwise_le(self, rhs: Self) -> $ty<bool> {
693                self.partial_cmp(rhs).map(|cmp| {
694                    matches!(cmp, Some(cmp::Ordering::Less | cmp::Ordering::Equal))
695                })
696            }
697            pub fn elementwise_gt(self, rhs: Self) -> $ty<bool> {
698                self.partial_cmp(rhs).map(|cmp| matches!(cmp, Some(cmp::Ordering::Greater)))
699            }
700            pub fn elementwise_ge(self, rhs: Self) -> $ty<bool> {
701                self.partial_cmp(rhs).map(|cmp| {
702                    matches!(cmp, Some(cmp::Ordering::Greater | cmp::Ordering::Equal))
703                })
704            }
705
706            /// Helper for comparison operations
707            fn partial_cmp(self, rhs: Self) -> $ty<Option<cmp::Ordering>> {
708                $ty {
709                    $(
710                        $component: self.$component.partial_cmp(&rhs.$component),
711                    )*
712                }
713            }
714        }
715
716        // Conversion in and out
717        impl<T> From<$ty<T>> for [T; $component_count] {
718            fn from(value: $ty<T>) -> Self {
719                [$( value.$component ),*]
720            }
721        }
722
723        // Irregular integer math: `$vec<u32>.abs()` exists even though it is the identity,
724        // but Rust doesn't have it.
725        impl $ty<i32> {
726            delegate_unary_methods_elementwise!(const { abs } ($($component)*));
727        }
728        impl $ty<u32> {
729            pub fn abs(self) -> Self { self }
730        }
731
732        // Boolean-specific functions
733        impl $ty<bool> {
734            /// As per WGSL [`any()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#any-builtin).
735            pub fn any(self) -> Scalar<bool> {
736                Scalar($( self.$component | )* false)
737            }
738            /// As per WGSL [`all()`](https://www.w3.org/TR/2025/CRD-WGSL-20250322/#all-builtin).
739            pub fn all(self) -> Scalar<bool> {
740                Scalar($( self.$component & )* true)
741            }
742        }
743    }
744}
745
746impl_vector_regular_fns!(Scalar 1 : 0);
747impl_vector_regular_fns!(Vec2 2 : x y);
748impl_vector_regular_fns!(Vec3 3 : x y z);
749impl_vector_regular_fns!(Vec4 4 : x y z w);
750
751// -------------------------------------------------------------------------------------------------
752// Impls that differ between `Vec*` and `Scalar`
753
754/// Applied to every `Vec` type but not `Scalar`
755macro_rules! impl_vector_not_scalar_fns {
756    ( $ty:ident $component_count:literal : $( $component:tt )* ) => {
757        impl<T> $ty<T> {
758            // User-friendly constructor, not used by translated code.
759            pub const fn new($( $component: T, )*) -> Self {
760                Self { $( $component, )* }
761            }
762
763            pub const fn from_scalars($( $component: Scalar<T>, )*) -> Self
764            where
765                T: Copy
766            {
767                Self { $( $component: $component.0, )* }
768            }
769        }
770
771        impl<T> From<[T; $component_count]> for $ty<T> {
772            fn from(value: [T; $component_count]) -> Self {
773                let [$( $component ),*] = value;
774                Self::new($( $component ),*)
775            }
776        }
777
778        impl_vector_scalar_integer_arithmetic!($ty, i32, $($component)*);
779        impl_vector_scalar_integer_arithmetic!($ty, u32, $($component)*);
780        impl_vector_scalar_float_arithmetic!($ty, f32, $($component)*);
781        impl_vector_scalar_float_arithmetic!($ty, f64, $($component)*);
782
783        // Commutative scalar-vector operators are derived from vector-scalar operators
784        impl<T> ops::Add<$ty<T>> for Scalar<T>
785        where
786            $ty<T>: ops::Add<Scalar<T>>
787        {
788            type Output = <$ty<T> as ops::Add<Scalar<T>>>::Output;
789            fn add(self, rhs: $ty<T>) -> Self::Output {
790                rhs + self
791            }
792        }
793        impl<T> ops::Mul<$ty<T>> for Scalar<T>
794        where
795            $ty<T>: ops::Mul<Scalar<T>>
796        {
797            type Output = <$ty<T> as ops::Mul<Scalar<T>>>::Output;
798            fn mul(self, rhs: $ty<T>) -> Self::Output {
799                rhs * self
800            }
801        }
802
803    }
804}
805
806impl_vector_not_scalar_fns!(Vec2 2 : x y);
807impl_vector_not_scalar_fns!(Vec3 3 : x y z);
808impl_vector_not_scalar_fns!(Vec4 4 : x y z w);
809
810impl<T> Scalar<T> {
811    pub fn new(value: T) -> Self {
812        Self(value)
813    }
814}
815impl<T> From<[T; 1]> for Scalar<T> {
816    fn from([value]: [T; 1]) -> Self {
817        Self(value)
818    }
819}
820
821// These impls must be per-primitive-type to pass trait coherence checking.
822macro_rules! impl_from_scalar_to_inner {
823    ($t:ty) => {
824        impl From<Scalar<$t>> for $t {
825            fn from(value: Scalar<$t>) -> Self {
826                value.0
827            }
828        }
829    };
830}
831impl_from_scalar_to_inner!(bool);
832impl_from_scalar_to_inner!(i32);
833impl_from_scalar_to_inner!(u32);
834impl_from_scalar_to_inner!(f32);
835impl_from_scalar_to_inner!(f64);
836
837// -------------------------------------------------------------------------------------------------
838// Irregular functions and impls
839
840impl<T> Scalar<T> {
841    /// Currently equivalent to `self.0` but can be used as a more strongly typed operation.
842    pub fn into_inner(self) -> T {
843        self.0
844    }
845
846    pub fn into_array_index(self) -> usize
847    where
848        T: Copy + TryInto<usize> + fmt::Debug,
849    {
850        match self.into_inner().try_into() {
851            Ok(index) => index,
852            Err(_) => panic!("impossible array index {self:?}"),
853        }
854    }
855}
856
857impl Scalar<bool> {
858    /// Returns the boolean value of this scalar.
859    ///
860    /// This method only exists for `Scalar<bool>`.
861    // (In the future when we support SIMD, this will be unavailable in the SIMD mode.)
862    #[mutants::skip] // causes infinite loops if mutated
863    pub fn into_branch_condition(self) -> bool {
864        self.0
865    }
866}
867
868impl<T> From<T> for Scalar<T> {
869    fn from(value: T) -> Self {
870        Self(value)
871    }
872}
873
874impl<T: Default> Default for Scalar<T> {
875    fn default() -> Self {
876        Self(Default::default())
877    }
878}
879
880// Constructor functions that take a mix of scalars and vectors.
881// These names must match those generated by `Writer::write_constructor_expression()`.
882macro_rules! impl_flattening_ctor {
883    (fn $fn_name:ident ( $($param:tt)* ) => ( $($arg:tt)* )) => {
884        pub const fn $fn_name ($($param)*) -> Self {
885            Self::new($($arg)*)
886        }
887    }
888}
889// Note: Copy bound is solely due to otherwise needing `feature(const_precise_live_drops)`.
890impl<T: Copy> Vec3<T> {
891    impl_flattening_ctor!(fn new_12(x: Scalar<T>, yz: Vec2<T>) => (x.0, yz.x, yz.y));
892    impl_flattening_ctor!(fn new_21(xy: Vec2<T>, z: Scalar<T>) => (xy.x, xy.y, z.0));
893}
894impl<T: Copy> Vec4<T> {
895    impl_flattening_ctor!(fn new_112(x: Scalar<T>, y: Scalar<T>, zw: Vec2<T>) => (x.0, y.0, zw.x, zw.y));
896    impl_flattening_ctor!(fn new_121(x: Scalar<T>, yz: Vec2<T>, w: Scalar<T>) => (x.0, yz.x, yz.y, w.0));
897    impl_flattening_ctor!(fn new_211(xy: Vec2<T>, z: Scalar<T>, w: Scalar<T>) => (xy.x, xy.y, z.0, w.0));
898    impl_flattening_ctor!(fn new_22(xy: Vec2<T>, zw: Vec2<T>) => (xy.x, xy.y, zw.x, zw.y));
899    impl_flattening_ctor!(fn new_13(x: Scalar<T>, yzw: Vec3<T>) => (x.0, yzw.x, yzw.y, yzw.z));
900    impl_flattening_ctor!(fn new_31(xyz: Vec3<T>, w: Scalar<T>) => (xyz.x, xyz.y, xyz.z, w.0));
901}
902
903// cross() is a function for Vec3 only
904impl<T> Vec3<T> {
905    // As per WGSL [`cross()`](https://www.w3.org/TR/2026/CRD-WGSL-20260310/#cross-builtin).
906    pub fn cross(self, rhs: Self) -> Self
907    where
908        T: Copy + ops::Mul<Output = T> + ops::Sub<Output = T>,
909    {
910        Self {
911            x: self.y * rhs.z - self.z * rhs.y,
912            y: self.z * rhs.x - self.x * rhs.z,
913            z: self.x * rhs.y - self.y * rhs.x,
914        }
915    }
916}
917
918// -------------------------------------------------------------------------------------------------
919// Swizzles and element accessors
920
921macro_rules! scalar_accessors {
922    ($get:ident $get_mut:ident $component:ident ) => {
923        /// Returns the
924        #[doc = stringify!($component)]
925        /// component of `self` as a [`Scalar`].
926        pub fn $get(self) -> Scalar<T> {
927            Scalar(self.$component)
928        }
929
930        /// Returns a reference to the
931        #[doc = stringify!($component)]
932        /// component of `self` as a [`Scalar`].
933        pub fn $get_mut(&mut self) -> &mut Scalar<T> {
934            // SAFETY: `Scalar` is `repr(transparent)`
935            unsafe { &mut *(&raw mut self.$component).cast::<Scalar<T>>() }
936        }
937    };
938}
939
940macro_rules! swizzle_fn {
941    ($name:ident $output:ident ($($cin:ident)*) ) => {
942        /// Takes the
943        #[doc = stringify!($($cin),*)]
944        /// elements of `self` and returns them in that order.
945        pub fn $name(self) -> $output<T> {
946            $output::new($(self.$cin,)*)
947        }
948    }
949}
950
951impl<T: Copy> Vec2<T> {
952    scalar_accessors!(x x_mut x);
953    scalar_accessors!(y y_mut y);
954    swizzle_fn!(xy Vec2(x y));
955    swizzle_fn!(yx Vec2(y x));
956}
957impl<T: Copy> Vec3<T> {
958    scalar_accessors!(x x_mut x);
959    scalar_accessors!(y y_mut y);
960    scalar_accessors!(z z_mut z);
961    swizzle_fn!(xy Vec2(x y));
962    swizzle_fn!(yx Vec2(y x));
963    swizzle_fn!(xyz Vec3(x y z));
964    swizzle_fn!(xzy Vec3(x z y));
965    swizzle_fn!(yxz Vec3(y x z));
966    swizzle_fn!(yzx Vec3(y z x));
967    swizzle_fn!(zxy Vec3(z x y));
968    swizzle_fn!(zyx Vec3(z y x));
969}
970impl<T: Copy> Vec4<T> {
971    scalar_accessors!(x x_mut x);
972    scalar_accessors!(y y_mut y);
973    scalar_accessors!(z z_mut z);
974    scalar_accessors!(w w_mut w);
975    swizzle_fn!(xy Vec2(x y));
976    swizzle_fn!(yx Vec2(y x));
977    swizzle_fn!(xyz Vec3(x y z));
978    swizzle_fn!(xzy Vec3(x z y));
979    swizzle_fn!(yxz Vec3(y x z));
980    swizzle_fn!(yzx Vec3(y z x));
981    swizzle_fn!(zxy Vec3(z x y));
982    swizzle_fn!(zyx Vec3(z y x));
983    swizzle_fn!(xyzw Vec4(x y z w));
984    swizzle_fn!(xywz Vec4(x y w z));
985    swizzle_fn!(xzwy Vec4(x z w y));
986    swizzle_fn!(xzyw Vec4(x z y w));
987    swizzle_fn!(xwyz Vec4(x w y z));
988    swizzle_fn!(xwzy Vec4(x w z y));
989    swizzle_fn!(yxzw Vec4(y x z w));
990    swizzle_fn!(yxwz Vec4(y x w z));
991    swizzle_fn!(yzxw Vec4(y z x w));
992    swizzle_fn!(yzwx Vec4(y z w x));
993    swizzle_fn!(ywzx Vec4(y w z x));
994    swizzle_fn!(ywxz Vec4(y w x z));
995    swizzle_fn!(zxyw Vec4(z x y w));
996    swizzle_fn!(zxwy Vec4(z x w y));
997    swizzle_fn!(zyxw Vec4(z y x w));
998    swizzle_fn!(zywx Vec4(z y w x));
999    swizzle_fn!(zwxy Vec4(z w x y));
1000    swizzle_fn!(zwyx Vec4(z w y x));
1001    swizzle_fn!(wxyz Vec4(w x y z));
1002    swizzle_fn!(wxzy Vec4(w x z y));
1003    swizzle_fn!(wyxz Vec4(w y x z));
1004    swizzle_fn!(wyzx Vec4(w y z x));
1005    swizzle_fn!(wzxy Vec4(w z x y));
1006    swizzle_fn!(wzyx Vec4(w z y x));
1007}