mewgpu 3.7.3

Maybe Easier Wgpu (mew), a thin abstraction over wgpu's chaos
//! A struct that may be written to a storage or uniform
//! [`wgpu::Buffer`](https://docs.rs/wgpu/latest/wgpu/struct.Buffer.html).
//!
//! See [`shader_struct`] for details.


#[allow(unused_imports)]
use crate::shaderprimitive;

/// Define a shader struct (to use in a **storage** or **uniform** buffer).
///
/// Give each field a name and a standard shader type from [`shaderprimitive`].
///
/// Uniform buffers are another can of worms, with their own weird alignment
/// rules. The best way to deal with them is probably to only use matrices or
/// arrays of multiples of 16 bytes.
///
/// Note that fields **must** be numbered correctly, starting from 0. This is
/// because I don't know how to teach macros how to count and still be able to
/// index tuples.  
/// Also, the fields are _not_ rearranged to be optimized to their alignment
/// rules, though they should be padded correctly for regular shader structs.
///
/// ```
/// shader_struct! { ShaderStruct [
///     0 int => I32,
///     1 mat => Mat4x4f,
///     2 float => F32,
/// ] }
///
/// buffer! { ShaderBuffer <ShaderStruct> as STORAGE | COPY_DST }
///
/// // Big enough to store 10 ShaderStructs, including padding
/// let buffer: ShaderBuffer = context.new_buffer(10);
/// ```
///
/// When you create a shader struct on the Rust side, its memory layout should
/// match exactly as it is shader-side. You can write directly to each field
/// (though everything's in arrays) and then safely-ish transmute it to a byte
/// slice to write to the buffer.
///
/// ```
/// let single_struct: ShaderStruct = (
///     [5_i32],
///     [[0.0, 1.0, 2.0, 3.0]; 4],
///     [4.0],
/// ).into();
/// let mut lotsa_structs = [single_struct; 10];
/// *lotsa_structs[7].float = [5.0];
///
/// context.queue.write_buffer(
///     &buffer,
///     some_offset * size_of::<ShaderStruct>() as u64,
///     lotsa_structs.as_byte_slice(),
/// );
/// ```
#[macro_export]
macro_rules! shader_struct {
    { $struct:ident [
        $( $num:tt $field:ident => $ty:ident ),* $(,)?
    ] } => {
        #[derive(Clone, Debug, PartialEq, PartialOrd)]
        #[repr(C)]
        pub struct $struct {
            $( pub $field: $crate::shaderprimitive::$ty, )*
            _padding: [u8; Self::PADDING],
        }

        impl $struct {
            //pub const SUM_SIZE: usize = ::std::mem::size_of::<( $( $ty, )* )>();
            const SUM_SIZE: usize = {
                #[repr(C)]
                struct SizeTest {
                    $( $field: $crate::shaderprimitive::$ty, )*
                }
                ::std::mem::size_of::<SizeTest>()
            };
            const MAX_SIZE: usize = $crate::max_size! { $( $crate::shaderprimitive::$ty )* };
            /// The total size of the struct, including padding for alignment.
            pub const BYTES: usize = Self::SUM_SIZE.next_multiple_of(Self::MAX_SIZE);
            /// The unused padding bytes necessary to bring the alignment up to a multiple of the
            /// biggest struct member's size. Aim to minimize this by rearranging members.
            pub const PADDING: usize = Self::BYTES - Self::SUM_SIZE;
        }

        impl $crate::shaderstruct::MewShaderStruct for $struct {
            type Bytes = [u8; Self::BYTES];
            type Inners = ( $( <$crate::shaderprimitive::$ty as $crate::shaderprimitive::MewShaderPrimitive>::Inner , )* );

            fn from_inners(inners: Self::Inners) -> Self {
                #[allow(unused_imports)]
                use $crate::shaderprimitive::MewShaderPrimitive;
                Self {
                    $( $field: $crate::shaderprimitive::$ty::from_inner(inners.$num), )*
                    _padding: [0; Self::PADDING],
                }
            }

            fn from_bytes(bytes: Self::Bytes) -> Self {
                unsafe { ::std::mem::transmute(bytes) }
            }

            fn zeroed() -> Self {
                unsafe {
                    Self {
                        //$( $field: [0; $crate::shader_struct! { @size $ty } ], )*
                        $( $field: ::std::mem::zeroed(), )*
                        _padding: [0; Self::PADDING],
                    }
                }
            }
        }


        impl From<[u8; Self::BYTES]> for $struct {
            fn from(bytes: [u8; Self::BYTES]) -> Self {
                use $crate::shaderstruct::MewShaderStruct;
                Self::from_bytes(bytes)
            }
        }
        impl From<( $( <$crate::shaderprimitive::$ty as $crate::shaderprimitive::MewShaderPrimitive>::Inner , )* )> for $struct {
            fn from(inners: ( $( <$crate::shaderprimitive::$ty as $crate::shaderprimitive::MewShaderPrimitive>::Inner , )* )) -> Self {
                use $crate::shaderstruct::MewShaderStruct;
                Self::from_inners(inners)
            }
        }

        impl AsRef<[u8; Self::BYTES]> for $struct {
            fn as_ref(&self) -> &[u8; Self::BYTES] {
                unsafe { &*::std::ptr::from_ref(self).cast() }
            }
        }
        impl AsMut<[u8; Self::BYTES]> for $struct {
            fn as_mut(&mut self) -> &mut [u8; Self::BYTES] {
                unsafe { &mut *::std::ptr::from_mut(self).cast() }
            }
        }

        impl Default for $struct {
            fn default() -> Self {
                use $crate::shaderstruct::MewShaderStruct;
                Self::zeroed()
            }
        }
    }
}
pub use shader_struct;


/// Trait for internal use to work with shader structs.
pub trait MewShaderStruct {
    /// A byte array (`[u8; N]`) the same size as the struct.
    type Bytes;
    /// A tuple of all internal types.
    type Inners;
    /// Build the struct using its internal types.
    fn from_inners(inners: Self::Inners) -> Self;
    /// Build the struct out of a byte array.
    fn from_bytes(bytes: Self::Bytes) -> Self;
    /// Build a struct with all fields zeroed.
    fn zeroed() -> Self;
}


/// Convenience trait to convert shader struct slices directly to byte slices.
///
/// Automatically implemented on `&[S]` where `S` is any shader struct.
pub trait MewShaderStructByteSlice {
    /// Get a byte slice to write directly to a buffer.
    fn as_byte_slice(&self) -> &[u8];
}

impl<S: MewShaderStruct> MewShaderStructByteSlice for [S] {
    fn as_byte_slice(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts(
                //self as *const [S] as *const u8,
                (&raw const *self).cast(),
                //size_of::<S>() * self.len(),
                size_of_val(self),
            )
        }
    }
}