From ef139f0957bda1361c52ac9dbdea313d47292ddd Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 14 Oct 2025 12:27:10 +0200 Subject: [PATCH 1/6] scalar or vector: unwrap is now a const fn cleanup --- crates/spirv-std/src/scalar.rs | 4 ++-- crates/spirv-std/src/vector.rs | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/crates/spirv-std/src/scalar.rs b/crates/spirv-std/src/scalar.rs index 520348be3a..6a30add998 100644 --- a/crates/spirv-std/src/scalar.rs +++ b/crates/spirv-std/src/scalar.rs @@ -1,6 +1,6 @@ //! Traits related to scalars. -use crate::vector::{VectorOrScalar, create_dim}; +use crate::vector::VectorOrScalar; use core::num::NonZeroUsize; /// Abstract trait representing a SPIR-V scalar type. @@ -21,7 +21,7 @@ macro_rules! impl_scalar { $( unsafe impl VectorOrScalar for $ty { type Scalar = Self; - const DIM: NonZeroUsize = create_dim(1); + const DIM: NonZeroUsize = NonZeroUsize::new(1).unwrap(); } unsafe impl Scalar for $ty {} )+ diff --git a/crates/spirv-std/src/vector.rs b/crates/spirv-std/src/vector.rs index f3ba4a42bb..f66ca7ad55 100644 --- a/crates/spirv-std/src/vector.rs +++ b/crates/spirv-std/src/vector.rs @@ -16,14 +16,6 @@ pub unsafe trait VectorOrScalar: Copy + Default + Send + Sync + 'static { const DIM: NonZeroUsize; } -/// replace with `NonZeroUsize::new(n).unwrap()` once `unwrap()` is const stabilized -pub(crate) const fn create_dim(n: usize) -> NonZeroUsize { - match NonZeroUsize::new(n) { - None => panic!("dim must not be 0"), - Some(n) => n, - } -} - /// Abstract trait representing a SPIR-V vector type. /// /// To implement this trait, your struct must be marked with: @@ -71,7 +63,7 @@ macro_rules! impl_vector { $($( unsafe impl VectorOrScalar for $vec { type Scalar = $scalar; - const DIM: NonZeroUsize = create_dim($dim); + const DIM: NonZeroUsize = NonZeroUsize::new($dim).unwrap(); } unsafe impl Vector<$scalar, $dim> for $vec {} )+)+ From 411436d7af17e934ec7e9257feb34e4ede90fe15 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 14 Oct 2025 13:10:06 +0200 Subject: [PATCH 2/6] scalar or vector: reexport all Scalar traits in lib.rs, make mods private apart from `mod float`, which contains functionality --- crates/spirv-std/src/arch.rs | 8 ++------ crates/spirv-std/src/arch/atomics.rs | 6 +----- crates/spirv-std/src/arch/subgroup.rs | 5 ++--- crates/spirv-std/src/image.rs | 19 ++++++++----------- crates/spirv-std/src/image/params.rs | 2 +- crates/spirv-std/src/lib.rs | 19 ++++++++++--------- crates/spirv-std/src/vector.rs | 2 +- tests/compiletests/ui/arch/all.rs | 2 -- tests/compiletests/ui/arch/any.rs | 2 -- .../ui/arch/debug_printf_type_checking.stderr | 7 ++----- 10 files changed, 27 insertions(+), 45 deletions(-) diff --git a/crates/spirv-std/src/arch.rs b/crates/spirv-std/src/arch.rs index d5c6c6a533..fe12b8ef56 100644 --- a/crates/spirv-std/src/arch.rs +++ b/crates/spirv-std/src/arch.rs @@ -4,12 +4,8 @@ //! These functions will typically map to a single instruction, and will perform //! no additional safety checks beyond type-checking. #[cfg(target_arch = "spirv")] -use crate::integer::Integer; -use crate::{ - integer::{SignedInteger, UnsignedInteger}, - scalar::Scalar, - vector::Vector, -}; +use crate::Integer; +use crate::{Scalar, SignedInteger, UnsignedInteger, Vector}; #[cfg(target_arch = "spirv")] use core::arch::asm; use glam::UVec2; diff --git a/crates/spirv-std/src/arch/atomics.rs b/crates/spirv-std/src/arch/atomics.rs index d818a0e0fd..38ff3d077c 100644 --- a/crates/spirv-std/src/arch/atomics.rs +++ b/crates/spirv-std/src/arch/atomics.rs @@ -1,11 +1,7 @@ #[cfg(target_arch = "spirv")] use core::arch::asm; -use crate::{ - float::Float, - integer::{Integer, SignedInteger, UnsignedInteger}, - number::Number, -}; +use crate::{Float, Integer, Number, SignedInteger, UnsignedInteger}; /// Atomically load through `ptr` using the given `SEMANTICS`. All subparts of /// the value that is loaded are read atomically with respect to all other diff --git a/crates/spirv-std/src/arch/subgroup.rs b/crates/spirv-std/src/arch/subgroup.rs index 05798a6f1d..eb524efe6a 100644 --- a/crates/spirv-std/src/arch/subgroup.rs +++ b/crates/spirv-std/src/arch/subgroup.rs @@ -1,10 +1,9 @@ +use crate::VectorOrScalar; #[cfg(target_arch = "spirv")] use crate::arch::barrier; -use crate::float::Float; -use crate::integer::{Integer, SignedInteger, UnsignedInteger}; #[cfg(target_arch = "spirv")] use crate::memory::{Scope, Semantics}; -use crate::vector::VectorOrScalar; +use crate::{Float, Integer, SignedInteger, UnsignedInteger}; #[cfg(target_arch = "spirv")] use core::arch::asm; diff --git a/crates/spirv-std/src/image.rs b/crates/spirv-std/src/image.rs index 8d4eef8b63..9fa844d087 100644 --- a/crates/spirv-std/src/image.rs +++ b/crates/spirv-std/src/image.rs @@ -1,24 +1,21 @@ //! Image types +pub use self::params::{ImageCoordinate, ImageCoordinateSubpassData, ImageSizeQuery, SampleType}; #[cfg(target_arch = "spirv")] -use crate::vector::VectorTruncateInto; +use crate::VectorTruncateInto; +pub use crate::macros::Image; +use crate::{Float, Integer, Sampler, Vector}; #[cfg(target_arch = "spirv")] use core::arch::asm; - -mod params; - -/// Contains extra image operands -pub mod sample_with; - -pub use self::params::{ImageCoordinate, ImageCoordinateSubpassData, ImageSizeQuery, SampleType}; -pub use crate::macros::Image; +use sample_with::{NoneTy, SampleParams, SomeTy}; pub use spirv_std_types::image_params::{ AccessQualifier, Arrayed, Dimensionality, ImageDepth, ImageFormat, Multisampled, Sampled, }; -use sample_with::{NoneTy, SampleParams, SomeTy}; +mod params; -use crate::{Sampler, float::Float, integer::Integer, vector::Vector}; +/// Contains extra image operands +pub mod sample_with; /// Re-export of primitive types to ensure the `Image` proc macro always points /// to the right type. diff --git a/crates/spirv-std/src/image/params.rs b/crates/spirv-std/src/image/params.rs index b4da908e55..cbfecdf5e5 100644 --- a/crates/spirv-std/src/image/params.rs +++ b/crates/spirv-std/src/image/params.rs @@ -1,5 +1,5 @@ use super::{Arrayed, Dimensionality, ImageFormat}; -use crate::{integer::Integer, scalar::Scalar, vector::Vector, vector::VectorTruncateInto}; +use crate::{Integer, Scalar, Vector, VectorTruncateInto}; /// Marker trait for arguments that accept single scalar values or vectors /// of scalars. Defines 2-, 3- and 4-component vector types based on the sample type. diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index 14e887b70f..ec72ff57ef 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -94,24 +94,29 @@ pub mod byte_addressable_buffer; pub mod float; pub mod image; pub mod indirect_command; -pub mod integer; +mod integer; pub mod matrix; pub mod memory; -pub mod number; +mod number; pub mod ray_tracing; mod runtime_array; mod sampler; -pub mod scalar; +mod scalar; pub(crate) mod sealed; mod typed_buffer; -pub mod vector; +mod vector; pub use self::sampler::Sampler; pub use crate::macros::Image; pub use byte_addressable_buffer::ByteAddressableBuffer; +pub use float::Float; +pub use integer::*; pub use num_traits; +pub use number::*; pub use runtime_array::*; +pub use scalar::*; pub use typed_buffer::*; +pub use vector::*; pub use glam; @@ -136,11 +141,7 @@ pub fn debug_printf_assert_is_type(ty: T) -> T { } #[doc(hidden)] -pub fn debug_printf_assert_is_vector< - TY: crate::scalar::Scalar, - V: crate::vector::Vector, - const SIZE: usize, ->( +pub fn debug_printf_assert_is_vector, const SIZE: usize>( vec: V, ) -> V { vec diff --git a/crates/spirv-std/src/vector.rs b/crates/spirv-std/src/vector.rs index f66ca7ad55..f9ac015479 100644 --- a/crates/spirv-std/src/vector.rs +++ b/crates/spirv-std/src/vector.rs @@ -1,6 +1,6 @@ //! Traits related to vectors. -use crate::scalar::Scalar; +use crate::Scalar; use core::num::NonZeroUsize; use glam::{Vec3Swizzles, Vec4Swizzles}; diff --git a/tests/compiletests/ui/arch/all.rs b/tests/compiletests/ui/arch/all.rs index 1d99c101cb..86731cb04e 100644 --- a/tests/compiletests/ui/arch/all.rs +++ b/tests/compiletests/ui/arch/all.rs @@ -1,8 +1,6 @@ // build-pass -use core::num::NonZeroUsize; use spirv_std::spirv; -use spirv_std::{scalar::Scalar, vector::Vector, vector::VectorOrScalar}; #[spirv(fragment)] pub fn main() { diff --git a/tests/compiletests/ui/arch/any.rs b/tests/compiletests/ui/arch/any.rs index e113927411..eecbcd6167 100644 --- a/tests/compiletests/ui/arch/any.rs +++ b/tests/compiletests/ui/arch/any.rs @@ -1,8 +1,6 @@ // build-pass -use core::num::NonZeroUsize; use spirv_std::spirv; -use spirv_std::{scalar::Scalar, vector::Vector, vector::VectorOrScalar}; #[spirv(fragment)] pub fn main() { diff --git a/tests/compiletests/ui/arch/debug_printf_type_checking.stderr b/tests/compiletests/ui/arch/debug_printf_type_checking.stderr index c1fd9eec3c..e0b52d851a 100644 --- a/tests/compiletests/ui/arch/debug_printf_type_checking.stderr +++ b/tests/compiletests/ui/arch/debug_printf_type_checking.stderr @@ -133,11 +133,8 @@ error[E0277]: the trait bound `{float}: Vector` is not satisfied note: required by a bound in `debug_printf_assert_is_vector` --> $SPIRV_STD_SRC/lib.rs: | - | pub fn debug_printf_assert_is_vector< - | ----------------------------- required by a bound in this function - | TY: crate::scalar::Scalar, - | V: crate::vector::Vector, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `debug_printf_assert_is_vector` + | pub fn debug_printf_assert_is_vector, const SIZE: usize>( + | ^^^^^^^^^^^^^^^^ required by this bound in `debug_printf_assert_is_vector` = note: this error originates in the macro `debug_printf` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types From 52de04782288e073caa00c0662746833c456a410 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 14 Oct 2025 15:01:01 +0200 Subject: [PATCH 3/6] scalar or vector: move all scalar traits and impl macros to `mod scalar` --- crates/spirv-std/src/float.rs | 18 ------ crates/spirv-std/src/integer.rs | 52 --------------- crates/spirv-std/src/lib.rs | 5 -- crates/spirv-std/src/number.rs | 15 ----- crates/spirv-std/src/scalar.rs | 110 ++++++++++++++++++++++++++++---- crates/spirv-std/src/sealed.rs | 12 ---- 6 files changed, 96 insertions(+), 116 deletions(-) delete mode 100644 crates/spirv-std/src/integer.rs delete mode 100644 crates/spirv-std/src/number.rs diff --git a/crates/spirv-std/src/float.rs b/crates/spirv-std/src/float.rs index 89d6a0745a..d9e8939376 100644 --- a/crates/spirv-std/src/float.rs +++ b/crates/spirv-std/src/float.rs @@ -4,24 +4,6 @@ use core::arch::asm; use glam::{Vec2, Vec4}; -/// Abstract trait representing a SPIR-V floating point type. -/// -/// # Safety -/// Implementing this trait on non-primitive-float types breaks assumptions of other unsafe code, -/// and should not be done. -pub unsafe trait Float: num_traits::Float + crate::scalar::Scalar + Default { - /// Width of the float, in bits. - const WIDTH: usize; -} - -unsafe impl Float for f32 { - const WIDTH: usize = 32; -} - -unsafe impl Float for f64 { - const WIDTH: usize = 64; -} - /// Converts two f32 values (floats) into two f16 values (halfs). The result is a u32, with the low /// 16 bits being the first f16, and the high 16 bits being the second f16. #[spirv_std_macros::gpu_only] diff --git a/crates/spirv-std/src/integer.rs b/crates/spirv-std/src/integer.rs deleted file mode 100644 index 083bae617a..0000000000 --- a/crates/spirv-std/src/integer.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Traits related to integers. - -/// Abstract trait representing any SPIR-V integer type. -/// -/// # Safety -/// Implementing this trait on non-primitive-integer types breaks assumptions of other unsafe code, -/// and should not be done. -pub unsafe trait Integer: num_traits::PrimInt + crate::scalar::Scalar { - /// Width of the integer, in bits. - const WIDTH: usize; - /// If the integer is signed: true means signed, false means unsigned. - const SIGNED: bool; -} - -/// A trait for being generic over signed integer types. -pub trait SignedInteger: Integer {} -/// A trait for being generic over unsigned integer types. -pub trait UnsignedInteger: Integer {} - -macro_rules! impl_numbers { - (impl UnsignedInteger for $typ:ty;) => { - unsafe impl Integer for $typ { - const WIDTH: usize = core::mem::size_of::<$typ>() * 8; - const SIGNED: bool = false; - } - - impl UnsignedInteger for $typ {} - }; - (impl SignedInteger for $typ:ty;) => { - unsafe impl Integer for $typ { - const WIDTH: usize = core::mem::size_of::<$typ>() * 8; - const SIGNED: bool = true; - } - - impl SignedInteger for $typ {} - }; - ($(impl $trait:ident for $typ:ty;)+) => { - $(impl_numbers!(impl $trait for $typ;);)+ - }; - -} - -impl_numbers! { - impl UnsignedInteger for u8; - impl UnsignedInteger for u16; - impl UnsignedInteger for u32; - impl UnsignedInteger for u64; - impl SignedInteger for i8; - impl SignedInteger for i16; - impl SignedInteger for i32; - impl SignedInteger for i64; -} diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index ec72ff57ef..f4810d9583 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -94,10 +94,8 @@ pub mod byte_addressable_buffer; pub mod float; pub mod image; pub mod indirect_command; -mod integer; pub mod matrix; pub mod memory; -mod number; pub mod ray_tracing; mod runtime_array; mod sampler; @@ -109,10 +107,7 @@ mod vector; pub use self::sampler::Sampler; pub use crate::macros::Image; pub use byte_addressable_buffer::ByteAddressableBuffer; -pub use float::Float; -pub use integer::*; pub use num_traits; -pub use number::*; pub use runtime_array::*; pub use scalar::*; pub use typed_buffer::*; diff --git a/crates/spirv-std/src/number.rs b/crates/spirv-std/src/number.rs deleted file mode 100644 index 20a195da1e..0000000000 --- a/crates/spirv-std/src/number.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Traits and helper functions related to numbers. - -/// Abstract trait representing a SPIR-V integer or floating-point type. -pub trait Number: crate::scalar::Scalar {} - -impl Number for u8 {} -impl Number for u16 {} -impl Number for u32 {} -impl Number for u64 {} -impl Number for i8 {} -impl Number for i16 {} -impl Number for i32 {} -impl Number for i64 {} -impl Number for f32 {} -impl Number for f64 {} diff --git a/crates/spirv-std/src/scalar.rs b/crates/spirv-std/src/scalar.rs index 6a30add998..e31b566d97 100644 --- a/crates/spirv-std/src/scalar.rs +++ b/crates/spirv-std/src/scalar.rs @@ -1,11 +1,10 @@ //! Traits related to scalars. -use crate::vector::VectorOrScalar; +use crate::VectorOrScalar; +use crate::sealed::Sealed; use core::num::NonZeroUsize; -/// Abstract trait representing a SPIR-V scalar type. -/// -/// Implemented on types that map to spirv "scalar" types, which includes: +/// Abstract trait representing a SPIR-V scalar type, which includes: /// * Floating-point type: f32, f64 /// * Integer type: u8, u16, u32, u64, i8, i16, i32, i64 /// * Boolean type: bool @@ -13,19 +12,102 @@ use core::num::NonZeroUsize; /// See the SPIRV spec on [Types](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_types). /// /// # Safety -/// Must only be implemented on spirv "scalar" types, as mentioned above. +/// Implementing this trait on non-scalar types breaks assumptions of other unsafe code, and should not be done. pub unsafe trait Scalar: VectorOrScalar + crate::sealed::Sealed {} +/// Abstract trait representing a SPIR-V integer or floating-point type. Unlike [`Scalar`], excludes the boolean type. +/// +/// # Safety +/// Implementing this trait on non-primitive-integer or non-primitive-float types breaks assumptions of other unsafe +/// code, and should not be done. +pub unsafe trait Number: Scalar {} + +/// Abstract trait representing any SPIR-V integer type. +/// +/// # Safety +/// Implementing this trait on non-primitive-integer types breaks assumptions of other unsafe code, +/// and should not be done. +pub unsafe trait Integer: num_traits::PrimInt + Number { + /// Width of the integer, in bits. + const WIDTH: usize; + /// If the integer is signed: true means signed, false means unsigned. + const SIGNED: bool; +} + +/// Abstract trait representing any SPIR-V signed integer type. +/// +/// # Safety +/// Implementing this trait on non-signed-integer types breaks assumptions of other unsafe code, +/// and should not be done. +pub unsafe trait SignedInteger: num_traits::Signed + Integer {} + +/// Abstract trait representing any SPIR-V unsigned integer type. +/// +/// # Safety +/// Implementing this trait on non-unsigned-integer types breaks assumptions of other unsafe code, +/// and should not be done. +pub unsafe trait UnsignedInteger: num_traits::Unsigned + Integer {} + +/// Abstract trait representing a SPIR-V floating point type. +/// +/// # Safety +/// Implementing this trait on non-primitive-float types breaks assumptions of other unsafe code, +/// and should not be done. +pub unsafe trait Float: num_traits::Float + Number { + /// Width of the float, in bits. + const WIDTH: usize; +} + macro_rules! impl_scalar { - ($($ty:ty),+) => { - $( - unsafe impl VectorOrScalar for $ty { - type Scalar = Self; - const DIM: NonZeroUsize = NonZeroUsize::new(1).unwrap(); - } - unsafe impl Scalar for $ty {} - )+ + (impl Scalar for $ty:ty;) => { + impl Sealed for $ty {} + unsafe impl VectorOrScalar for $ty { + type Scalar = Self; + const DIM: NonZeroUsize = NonZeroUsize::new(1).unwrap(); + } + unsafe impl Scalar for $ty {} + }; + (impl Number for $ty:ty;) => { + unsafe impl Number for $ty {} + impl_scalar!(impl Scalar for $ty;); + }; + (impl UnsignedInteger for $ty:ty;) => { + unsafe impl Integer for $ty { + const WIDTH: usize = core::mem::size_of::<$ty>() * 8; + const SIGNED: bool = false; + } + unsafe impl UnsignedInteger for $ty {} + impl_scalar!(impl Number for $ty;); + }; + (impl SignedInteger for $ty:ty;) => { + unsafe impl Integer for $ty { + const WIDTH: usize = core::mem::size_of::<$ty>() * 8; + const SIGNED: bool = true; + } + unsafe impl SignedInteger for $ty {} + impl_scalar!(impl Number for $ty;); + }; + (impl Float for $ty:ty;) => { + unsafe impl Float for $ty { + const WIDTH: usize = core::mem::size_of::<$ty>() * 8; + } + impl_scalar!(impl Number for $ty;); + }; + ($(impl $trait:ident for $ty:ty;)+) => { + $(impl_scalar!(impl $trait for $ty;);)+ }; } -impl_scalar!(bool, f32, f64, u8, u16, u32, u64, i8, i16, i32, i64); +impl_scalar! { + impl UnsignedInteger for u8; + impl UnsignedInteger for u16; + impl UnsignedInteger for u32; + impl UnsignedInteger for u64; + impl SignedInteger for i8; + impl SignedInteger for i16; + impl SignedInteger for i32; + impl SignedInteger for i64; + impl Float for f32; + impl Float for f64; + impl Scalar for bool; +} diff --git a/crates/spirv-std/src/sealed.rs b/crates/spirv-std/src/sealed.rs index 7c8cdb5789..421ed9018b 100644 --- a/crates/spirv-std/src/sealed.rs +++ b/crates/spirv-std/src/sealed.rs @@ -2,18 +2,6 @@ /// of `spirv-std`. pub trait Sealed {} -impl Sealed for bool {} -impl Sealed for f32 {} -impl Sealed for f64 {} -impl Sealed for u8 {} -impl Sealed for u16 {} -impl Sealed for u32 {} -impl Sealed for u64 {} -impl Sealed for i8 {} -impl Sealed for i16 {} -impl Sealed for i32 {} -impl Sealed for i64 {} - impl Sealed for glam::Vec2 {} impl Sealed for glam::Vec3 {} impl Sealed for glam::Vec4 {} From 8263a2f76343a67e8d6672a844e230c66365523c Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 14 Oct 2025 15:45:58 +0200 Subject: [PATCH 4/6] scalar or vector: minor vector code cleanup --- crates/spirv-std/src/sealed.rs | 15 ------------ crates/spirv-std/src/vector.rs | 45 ++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/crates/spirv-std/src/sealed.rs b/crates/spirv-std/src/sealed.rs index 421ed9018b..1080c038a5 100644 --- a/crates/spirv-std/src/sealed.rs +++ b/crates/spirv-std/src/sealed.rs @@ -1,18 +1,3 @@ /// A marker trait used to prevent other traits from being implemented outside /// of `spirv-std`. pub trait Sealed {} - -impl Sealed for glam::Vec2 {} -impl Sealed for glam::Vec3 {} -impl Sealed for glam::Vec4 {} -impl Sealed for glam::DVec2 {} -impl Sealed for glam::DVec3 {} -impl Sealed for glam::DVec4 {} -impl Sealed for glam::UVec2 {} -impl Sealed for glam::UVec3 {} -impl Sealed for glam::UVec4 {} -impl Sealed for glam::IVec2 {} -impl Sealed for glam::IVec3 {} -impl Sealed for glam::IVec4 {} - -impl Sealed for glam::Vec3A {} diff --git a/crates/spirv-std/src/vector.rs b/crates/spirv-std/src/vector.rs index f9ac015479..45cfa53e70 100644 --- a/crates/spirv-std/src/vector.rs +++ b/crates/spirv-std/src/vector.rs @@ -1,6 +1,7 @@ //! Traits related to vectors. use crate::Scalar; +use crate::sealed::Sealed; use core::num::NonZeroUsize; use glam::{Vec3Swizzles, Vec4Swizzles}; @@ -54,28 +55,46 @@ pub unsafe trait VectorOrScalar: Copy + Default + Send + Sync + 'static { /// /// /// # Safety -/// Must only be implemented on types that the spirv codegen emits as valid `OpTypeVector`. This includes all structs -/// marked with `#[rust_gpu::vector::v1]`, like [`glam`]'s non-SIMD "scalar" vector types. +/// * Must only be implemented on types that the spirv codegen emits as valid `OpTypeVector`. This includes all structs +/// marked with `#[rust_gpu::vector::v1]`, like [`glam`]'s non-SIMD "scalar" vector types. +/// * `VectorOrScalar::DIM == N`, since const equality is behind rustc feature `associated_const_equality` +// Note(@firestar99) I would like to have these two generics be associated types instead. Doesn't make much sense for +// a vector type to implement this interface multiple times with different Scalar types or N, after all. +// While it's possible with `T: Scalar`, it's not with `const N: usize`, since some impl blocks in `image::params` need +// to be conditional on a specific N value. And you can only express that with const generics, but not with associated +// constants due to lack of const generics support in rustc. pub unsafe trait Vector: VectorOrScalar {} macro_rules! impl_vector { - ($($scalar:ty: $($vec:ty => $dim:literal),+;)+) => { - $($( - unsafe impl VectorOrScalar for $vec { + ($($ty:ty: [$scalar:ty; $n:literal];)+) => { + $( + impl Sealed for $ty {} + unsafe impl VectorOrScalar for $ty { type Scalar = $scalar; - const DIM: NonZeroUsize = NonZeroUsize::new($dim).unwrap(); + const DIM: NonZeroUsize = NonZeroUsize::new($n).unwrap(); } - unsafe impl Vector<$scalar, $dim> for $vec {} - )+)+ + unsafe impl Vector<$scalar, $n> for $ty {} + )+ }; } impl_vector! { - f32: glam::Vec2 => 2, glam::Vec3 => 3, glam::Vec3A => 3, glam::Vec4 => 4; - f64: glam::DVec2 => 2, glam::DVec3 => 3, glam::DVec4 => 4; - u32: glam::UVec2 => 2, glam::UVec3 => 3, glam::UVec4 => 4; - i32: glam::IVec2 => 2, glam::IVec3 => 3, glam::IVec4 => 4; - bool: glam::BVec2 => 2, glam::BVec3 => 3, glam::BVec4 => 4; + glam::Vec2: [f32; 2]; + glam::Vec3: [f32; 3]; + glam::Vec3A: [f32; 3]; + glam::Vec4: [f32; 4]; + glam::DVec2: [f64; 2]; + glam::DVec3: [f64; 3]; + glam::DVec4: [f64; 4]; + glam::UVec2: [u32; 2]; + glam::UVec3: [u32; 3]; + glam::UVec4: [u32; 4]; + glam::IVec2: [i32; 2]; + glam::IVec3: [i32; 3]; + glam::IVec4: [i32; 4]; + glam::BVec2: [bool; 2]; + glam::BVec3: [bool; 3]; + glam::BVec4: [bool; 4]; } /// Trait that implements slicing of a vector into a scalar or vector of lower dimensions, by From 7554b0157f78a18e38e07e8b74442a2ef77bd077 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 14 Oct 2025 16:00:31 +0200 Subject: [PATCH 5/6] scalar or vector: rename `VectorOrScalar` to `ScalarOrVector` and give it its own mod --- crates/spirv-std/src/arch/subgroup.rs | 24 ++++++++++++------------ crates/spirv-std/src/lib.rs | 3 ++- crates/spirv-std/src/scalar.rs | 8 ++++---- crates/spirv-std/src/scalar_or_vector.rs | 20 ++++++++++++++++++++ crates/spirv-std/src/sealed.rs | 3 --- crates/spirv-std/src/vector.rs | 20 ++++---------------- 6 files changed, 42 insertions(+), 36 deletions(-) create mode 100644 crates/spirv-std/src/scalar_or_vector.rs delete mode 100644 crates/spirv-std/src/sealed.rs diff --git a/crates/spirv-std/src/arch/subgroup.rs b/crates/spirv-std/src/arch/subgroup.rs index eb524efe6a..fafc30ffc2 100644 --- a/crates/spirv-std/src/arch/subgroup.rs +++ b/crates/spirv-std/src/arch/subgroup.rs @@ -1,4 +1,4 @@ -use crate::VectorOrScalar; +use crate::ScalarOrVector; #[cfg(target_arch = "spirv")] use crate::arch::barrier; #[cfg(target_arch = "spirv")] @@ -243,7 +243,7 @@ pub fn subgroup_any(predicate: bool) -> bool { #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformAllEqual")] #[inline] -pub fn subgroup_all_equal(value: T) -> bool { +pub fn subgroup_all_equal(value: T) -> bool { let mut result = false; unsafe { @@ -286,7 +286,7 @@ pub fn subgroup_all_equal(value: T) -> bool { #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformBroadcast")] #[inline] -pub unsafe fn subgroup_broadcast(value: T, id: u32) -> T { +pub unsafe fn subgroup_broadcast(value: T, id: u32) -> T { let mut result = T::default(); unsafe { @@ -319,7 +319,7 @@ pub unsafe fn subgroup_broadcast(value: T, id: u32) -> T { #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformBroadcastFirst")] #[inline] -pub fn subgroup_broadcast_first(value: T) -> T { +pub fn subgroup_broadcast_first(value: T) -> T { let mut result = T::default(); unsafe { @@ -594,7 +594,7 @@ pub fn subgroup_ballot_find_msb(value: SubgroupMask) -> u32 { #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformShuffle")] #[inline] -pub fn subgroup_shuffle(value: T, id: u32) -> T { +pub fn subgroup_shuffle(value: T, id: u32) -> T { let mut result = T::default(); unsafe { @@ -635,7 +635,7 @@ pub fn subgroup_shuffle(value: T, id: u32) -> T { #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformShuffleXor")] #[inline] -pub fn subgroup_shuffle_xor(value: T, mask: u32) -> T { +pub fn subgroup_shuffle_xor(value: T, mask: u32) -> T { let mut result = T::default(); unsafe { @@ -676,7 +676,7 @@ pub fn subgroup_shuffle_xor(value: T, mask: u32) -> T { #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformShuffleUp")] #[inline] -pub fn subgroup_shuffle_up(value: T, delta: u32) -> T { +pub fn subgroup_shuffle_up(value: T, delta: u32) -> T { let mut result = T::default(); unsafe { @@ -717,7 +717,7 @@ pub fn subgroup_shuffle_up(value: T, delta: u32) -> T { #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformShuffleDown")] #[inline] -pub fn subgroup_shuffle_down(value: T, delta: u32) -> T { +pub fn subgroup_shuffle_down(value: T, delta: u32) -> T { let mut result = T::default(); unsafe { @@ -744,7 +744,7 @@ macro_rules! macro_subgroup_op { #[spirv_std_macros::gpu_only] #[doc(alias = $asm_op)] #[inline] - pub fn $name>( + pub fn $name>( value: I, ) -> I { let mut result = I::default(); @@ -772,7 +772,7 @@ macro_rules! macro_subgroup_op_clustered { #[spirv_std_macros::gpu_only] #[doc(alias = $asm_op)] #[inline] - pub unsafe fn $name>( + pub unsafe fn $name>( value: I, ) -> I { const { @@ -1344,7 +1344,7 @@ Requires Capability `GroupNonUniformArithmetic` and `GroupNonUniformClustered`. #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformQuadBroadcast")] #[inline] -pub fn subgroup_quad_broadcast(value: T, index: u32) -> T { +pub fn subgroup_quad_broadcast(value: T, index: u32) -> T { let mut result = T::default(); unsafe { @@ -1427,7 +1427,7 @@ pub enum QuadDirection { #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformQuadSwap")] #[inline] -pub fn subgroup_quad_swap(value: T) -> T { +pub fn subgroup_quad_swap(value: T) -> T { let mut result = T::default(); unsafe { diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index f4810d9583..74dcf153da 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -100,7 +100,7 @@ pub mod ray_tracing; mod runtime_array; mod sampler; mod scalar; -pub(crate) mod sealed; +mod scalar_or_vector; mod typed_buffer; mod vector; @@ -110,6 +110,7 @@ pub use byte_addressable_buffer::ByteAddressableBuffer; pub use num_traits; pub use runtime_array::*; pub use scalar::*; +pub use scalar_or_vector::*; pub use typed_buffer::*; pub use vector::*; diff --git a/crates/spirv-std/src/scalar.rs b/crates/spirv-std/src/scalar.rs index e31b566d97..b4774ea861 100644 --- a/crates/spirv-std/src/scalar.rs +++ b/crates/spirv-std/src/scalar.rs @@ -1,6 +1,6 @@ //! Traits related to scalars. -use crate::VectorOrScalar; +use crate::ScalarOrVector; use crate::sealed::Sealed; use core::num::NonZeroUsize; @@ -13,7 +13,7 @@ use core::num::NonZeroUsize; /// /// # Safety /// Implementing this trait on non-scalar types breaks assumptions of other unsafe code, and should not be done. -pub unsafe trait Scalar: VectorOrScalar + crate::sealed::Sealed {} +pub unsafe trait Scalar: ScalarOrVector + crate::sealed::Sealed {} /// Abstract trait representing a SPIR-V integer or floating-point type. Unlike [`Scalar`], excludes the boolean type. /// @@ -61,9 +61,9 @@ pub unsafe trait Float: num_traits::Float + Number { macro_rules! impl_scalar { (impl Scalar for $ty:ty;) => { impl Sealed for $ty {} - unsafe impl VectorOrScalar for $ty { + unsafe impl ScalarOrVector for $ty { type Scalar = Self; - const DIM: NonZeroUsize = NonZeroUsize::new(1).unwrap(); + const N: NonZeroUsize = NonZeroUsize::new(1).unwrap(); } unsafe impl Scalar for $ty {} }; diff --git a/crates/spirv-std/src/scalar_or_vector.rs b/crates/spirv-std/src/scalar_or_vector.rs new file mode 100644 index 0000000000..0ce0751ddd --- /dev/null +++ b/crates/spirv-std/src/scalar_or_vector.rs @@ -0,0 +1,20 @@ +use crate::{Scalar, Vector}; +use core::num::NonZeroUsize; + +pub(crate) mod sealed { + /// A marker trait used to prevent other traits from being implemented outside + /// of `spirv-std`. + pub trait Sealed {} +} + +/// Abstract trait representing either a [`Scalar`] or [`Vector`] type. +/// +/// # Safety +/// Your type must also implement [`Scalar`] or [`Vector`], see their safety sections as well. +pub unsafe trait ScalarOrVector: Copy + Default + Send + Sync + 'static { + /// Either the scalar component type of the vector or the scalar itself. + type Scalar: Scalar; + + /// The dimension of the vector, or 1 if it is a scalar + const N: NonZeroUsize; +} diff --git a/crates/spirv-std/src/sealed.rs b/crates/spirv-std/src/sealed.rs deleted file mode 100644 index 1080c038a5..0000000000 --- a/crates/spirv-std/src/sealed.rs +++ /dev/null @@ -1,3 +0,0 @@ -/// A marker trait used to prevent other traits from being implemented outside -/// of `spirv-std`. -pub trait Sealed {} diff --git a/crates/spirv-std/src/vector.rs b/crates/spirv-std/src/vector.rs index 45cfa53e70..0389424df0 100644 --- a/crates/spirv-std/src/vector.rs +++ b/crates/spirv-std/src/vector.rs @@ -1,22 +1,10 @@ //! Traits related to vectors. -use crate::Scalar; use crate::sealed::Sealed; +use crate::{Scalar, ScalarOrVector}; use core::num::NonZeroUsize; use glam::{Vec3Swizzles, Vec4Swizzles}; -/// Abstract trait representing either a vector or a scalar type. -/// -/// # Safety -/// Your type must also implement [`Vector`] or [`Scalar`], see their safety sections as well. -pub unsafe trait VectorOrScalar: Copy + Default + Send + Sync + 'static { - /// Either the scalar component type of the vector or the scalar itself. - type Scalar: Scalar; - - /// The dimension of the vector, or 1 if it is a scalar - const DIM: NonZeroUsize; -} - /// Abstract trait representing a SPIR-V vector type. /// /// To implement this trait, your struct must be marked with: @@ -63,15 +51,15 @@ pub unsafe trait VectorOrScalar: Copy + Default + Send + Sync + 'static { // While it's possible with `T: Scalar`, it's not with `const N: usize`, since some impl blocks in `image::params` need // to be conditional on a specific N value. And you can only express that with const generics, but not with associated // constants due to lack of const generics support in rustc. -pub unsafe trait Vector: VectorOrScalar {} +pub unsafe trait Vector: ScalarOrVector {} macro_rules! impl_vector { ($($ty:ty: [$scalar:ty; $n:literal];)+) => { $( impl Sealed for $ty {} - unsafe impl VectorOrScalar for $ty { + unsafe impl ScalarOrVector for $ty { type Scalar = $scalar; - const DIM: NonZeroUsize = NonZeroUsize::new($n).unwrap(); + const N: NonZeroUsize = NonZeroUsize::new($n).unwrap(); } unsafe impl Vector<$scalar, $n> for $ty {} )+ From 80dda7d0451f2710c98983eee52b632cf67db027 Mon Sep 17 00:00:00 2001 From: firestar99 Date: Tue, 14 Oct 2025 19:37:05 +0200 Subject: [PATCH 6/6] scalar or vector: fix unused import without docs --- crates/spirv-std/src/scalar_or_vector.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/spirv-std/src/scalar_or_vector.rs b/crates/spirv-std/src/scalar_or_vector.rs index 0ce0751ddd..87b0073241 100644 --- a/crates/spirv-std/src/scalar_or_vector.rs +++ b/crates/spirv-std/src/scalar_or_vector.rs @@ -1,4 +1,4 @@ -use crate::{Scalar, Vector}; +use crate::Scalar; use core::num::NonZeroUsize; pub(crate) mod sealed { @@ -11,6 +11,8 @@ pub(crate) mod sealed { /// /// # Safety /// Your type must also implement [`Scalar`] or [`Vector`], see their safety sections as well. +/// +/// [`Vector`]: crate::Vector pub unsafe trait ScalarOrVector: Copy + Default + Send + Sync + 'static { /// Either the scalar component type of the vector or the scalar itself. type Scalar: Scalar;