spirv_std/
vector.rs

1//! Traits related to vectors.
2
3use crate::scalar::Scalar;
4use core::num::NonZeroUsize;
5use glam::{Vec3Swizzles, Vec4Swizzles};
6
7/// Abstract trait representing either a vector or a scalar type.
8///
9/// # Safety
10/// Implementing this trait on non-scalar or non-vector types may break assumptions about other
11/// unsafe code, and should not be done.
12pub unsafe trait VectorOrScalar: Copy + Default + Send + Sync + 'static {
13    /// Either the scalar component type of the vector or the scalar itself.
14    type Scalar: Scalar;
15
16    /// The dimension of the vector, or 1 if it is a scalar
17    const DIM: NonZeroUsize;
18}
19
20/// replace with `NonZeroUsize::new(n).unwrap()` once `unwrap()` is const stabilized
21pub(crate) const fn create_dim(n: usize) -> NonZeroUsize {
22    match NonZeroUsize::new(n) {
23        None => panic!("dim must not be 0"),
24        Some(n) => n,
25    }
26}
27
28/// Abstract trait representing a SPIR-V vector type.
29///
30/// # Safety
31/// Implementing this trait on non-simd-vector types breaks assumptions of other unsafe code, and
32/// should not be done.
33pub unsafe trait Vector<T: Scalar, const N: usize>: VectorOrScalar<Scalar = T> {}
34
35macro_rules! impl_vector {
36    ($($scalar:ty: $($vec:ty => $dim:literal),+;)+) => {
37        $($(
38            unsafe impl VectorOrScalar for $vec {
39                type Scalar = $scalar;
40                const DIM: NonZeroUsize = create_dim($dim);
41            }
42            unsafe impl Vector<$scalar, $dim> for $vec {}
43        )+)+
44    };
45}
46
47impl_vector! {
48    f32: glam::Vec2 => 2, glam::Vec3 => 3, glam::Vec3A => 3, glam::Vec4 => 4;
49    f64: glam::DVec2 => 2, glam::DVec3 => 3, glam::DVec4 => 4;
50    u32: glam::UVec2 => 2, glam::UVec3 => 3, glam::UVec4 => 4;
51    i32: glam::IVec2 => 2, glam::IVec3 => 3, glam::IVec4 => 4;
52}
53
54/// Trait that implements slicing of a vector into a scalar or vector of lower dimensions, by
55/// ignoring the higher dimensions
56pub trait VectorTruncateInto<T> {
57    /// Slices the vector into a lower dimensional type by ignoring the higher components
58    fn truncate_into(self) -> T;
59}
60
61macro_rules! vec_trunc_impl {
62    ($a:ty, $b:ty, $self:ident $(.$($e:tt)*)?) => {
63        impl VectorTruncateInto<$a> for $b {
64            fn truncate_into($self) -> $a {
65                $self $(. $($e)*)?
66            }
67        }
68    };
69}
70macro_rules! vec_trunc_impls {
71    ($s:ty, $v2:ty, $v3:ty, $v4:ty) => {
72        vec_trunc_impl! {$s, $s, self}
73        vec_trunc_impl! {$s, $v2, self.x}
74        vec_trunc_impl! {$s, $v3, self.x}
75        vec_trunc_impl! {$s, $v4, self.x}
76
77        vec_trunc_impl! {$v2, $v2, self}
78        vec_trunc_impl! {$v2, $v3, self.xy()}
79        vec_trunc_impl! {$v2, $v4, self.xy()}
80
81        vec_trunc_impl! {$v3, $v3, self}
82        vec_trunc_impl! {$v3, $v4, self.xyz()}
83
84        vec_trunc_impl! {$v4, $v4, self}
85    };
86}
87
88vec_trunc_impls! { f32, glam::Vec2, glam::Vec3, glam::Vec4 }
89vec_trunc_impls! { f64, glam::DVec2, glam::DVec3, glam::DVec4 }
90vec_trunc_impls! { i32, glam::IVec2, glam::IVec3, glam::IVec4 }
91vec_trunc_impls! { u32, glam::UVec2, glam::UVec3, glam::UVec4 }