encase/types/
array.rs

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