encase/types/
array.rs

1use crate::core::{
2    BufferMut, BufferRef, CreateFrom, Metadata, ReadFrom, Reader, ShaderSize, ShaderType,
3    SizeValue, WriteInto, Writer,
4};
5
6pub struct ArrayMetadata {
7    pub stride: SizeValue,
8    pub el_padding: u64,
9}
10
11impl Metadata<ArrayMetadata> {
12    pub const fn stride(self) -> SizeValue {
13        self.extra.stride
14    }
15
16    pub const fn el_padding(self) -> u64 {
17        self.extra.el_padding
18    }
19}
20
21impl<T: ShaderType + ShaderSize, const N: usize> ShaderType for [T; N] {
22    type ExtraMetadata = ArrayMetadata;
23    const METADATA: Metadata<Self::ExtraMetadata> = {
24        let alignment = T::METADATA.alignment();
25        let el_size = SizeValue::from(T::SHADER_SIZE);
26
27        let stride = alignment.round_up_size(el_size);
28        let el_padding = alignment.padding_needed_for(el_size.get());
29
30        let size = match N {
31            0 => panic!("0 sized arrays are not supported!"),
32            val => stride.mul(val as u64),
33        };
34
35        Metadata {
36            alignment,
37            has_uniform_min_alignment: true,
38            min_size: size,
39            is_pod: T::METADATA.is_pod() && el_padding == 0,
40            extra: ArrayMetadata { stride, el_padding },
41        }
42    };
43
44    const UNIFORM_COMPAT_ASSERT: fn() = || {
45        crate::utils::consume_zsts([
46            <T as ShaderType>::UNIFORM_COMPAT_ASSERT(),
47            if let Some(min_alignment) = Self::METADATA.uniform_min_alignment() {
48                const_panic::concat_assert!(
49                    min_alignment.is_aligned(Self::METADATA.stride().get()),
50                    "array stride must be a multiple of ",
51                    min_alignment.get(),
52                    " (current stride: ",
53                    Self::METADATA.stride().get(),
54                    ")"
55                );
56            },
57        ]);
58    };
59}
60
61impl<T: ShaderSize, const N: usize> ShaderSize for [T; N] {}
62
63impl<T: WriteInto, const N: usize> WriteInto for [T; N]
64where
65    Self: ShaderType<ExtraMetadata = ArrayMetadata>,
66{
67    #[inline]
68    fn write_into<B: BufferMut>(&self, writer: &mut Writer<B>) {
69        if_pod_and_little_endian!(if pod_and_little_endian {
70            let ptr = self.as_ptr() as *const u8;
71            let byte_slice: &[u8] =
72                unsafe { core::slice::from_raw_parts(ptr, core::mem::size_of::<Self>()) };
73            writer.write_slice(byte_slice);
74        } else {
75            for elem in self {
76                WriteInto::write_into(elem, writer);
77                writer.advance(Self::METADATA.el_padding() as usize);
78            }
79        });
80    }
81}
82
83impl<T: ReadFrom, const N: usize> ReadFrom for [T; N]
84where
85    Self: ShaderType<ExtraMetadata = ArrayMetadata>,
86{
87    #[inline]
88    fn read_from<B: BufferRef>(&mut self, reader: &mut Reader<B>) {
89        if_pod_and_little_endian!(if pod_and_little_endian {
90            let ptr = self.as_mut_ptr() as *mut u8;
91            let byte_slice: &mut [u8] =
92                unsafe { core::slice::from_raw_parts_mut(ptr, core::mem::size_of::<Self>()) };
93            reader.read_slice(byte_slice);
94        } else {
95            for elem in self {
96                ReadFrom::read_from(elem, reader);
97                reader.advance(Self::METADATA.el_padding() as usize);
98            }
99        });
100    }
101}
102
103impl<T: CreateFrom, const N: usize> CreateFrom for [T; N]
104where
105    Self: ShaderType<ExtraMetadata = ArrayMetadata>,
106{
107    #[inline]
108    fn create_from<B: BufferRef>(reader: &mut Reader<B>) -> Self {
109        if_pod_and_little_endian!(if pod_and_little_endian {
110            let mut me = core::mem::MaybeUninit::zeroed();
111            let ptr: *mut core::mem::MaybeUninit<Self> = &mut me;
112            let ptr = ptr.cast::<u8>();
113            let byte_slice: &mut [u8] =
114                unsafe { core::slice::from_raw_parts_mut(ptr, core::mem::size_of::<Self>()) };
115            reader.read_slice(byte_slice);
116            // SAFETY: All values were properly initialized by reading the bytes.
117            unsafe { me.assume_init() }
118        } else {
119            core::array::from_fn(|_| {
120                let res = CreateFrom::create_from(reader);
121                reader.advance(Self::METADATA.el_padding() as usize);
122                res
123            })
124        })
125    }
126}