encase/core/traits.rs
1use std::num::NonZeroU64;
2
3use super::{AlignmentValue, BufferMut, BufferRef, Reader, SizeValue, Writer};
4
5const UNIFORM_MIN_ALIGNMENT: AlignmentValue = AlignmentValue::new(16);
6
7pub struct Metadata<E> {
8 pub alignment: AlignmentValue,
9 pub has_uniform_min_alignment: bool,
10 pub min_size: SizeValue,
11 pub is_pod: bool,
12 pub extra: E,
13}
14
15impl Metadata<()> {
16 pub const fn from_alignment_and_size(alignment: u64, size: u64) -> Self {
17 Self {
18 alignment: AlignmentValue::new(alignment),
19 has_uniform_min_alignment: false,
20 min_size: SizeValue::new(size),
21 is_pod: false,
22 extra: (),
23 }
24 }
25}
26
27// using forget() avoids "destructors cannot be evaluated at compile-time" error
28// track #![feature(const_precise_live_drops)] (https://github.com/rust-lang/rust/issues/73255)
29
30impl<E> Metadata<E> {
31 #[inline]
32 pub const fn alignment(self) -> AlignmentValue {
33 let value = self.alignment;
34 core::mem::forget(self);
35 value
36 }
37
38 #[inline]
39 pub const fn uniform_min_alignment(self) -> Option<AlignmentValue> {
40 let value = self.has_uniform_min_alignment;
41 core::mem::forget(self);
42 match value {
43 true => Some(UNIFORM_MIN_ALIGNMENT),
44 false => None,
45 }
46 }
47
48 #[inline]
49 pub const fn min_size(self) -> SizeValue {
50 let value = self.min_size;
51 core::mem::forget(self);
52 value
53 }
54
55 #[inline]
56 pub const fn is_pod(self) -> bool {
57 let value = self.is_pod;
58 core::mem::forget(self);
59 value
60 }
61
62 #[inline]
63 pub const fn pod(mut self) -> Self {
64 self.is_pod = true;
65 self
66 }
67
68 #[inline]
69 pub const fn no_pod(mut self) -> Self {
70 self.is_pod = false;
71 self
72 }
73}
74
75/// Base trait for all [WGSL host-shareable types](https://gpuweb.github.io/gpuweb/wgsl/#host-shareable-types)
76pub trait ShaderType {
77 #[doc(hidden)]
78 type ExtraMetadata;
79 #[doc(hidden)]
80 const METADATA: Metadata<Self::ExtraMetadata>;
81
82 /// Represents the minimum size of `Self` (equivalent to [GPUBufferBindingLayout.minBindingSize](https://gpuweb.github.io/gpuweb/#dom-gpubufferbindinglayout-minbindingsize))
83 ///
84 /// For [WGSL fixed-footprint types](https://gpuweb.github.io/gpuweb/wgsl/#fixed-footprint-types)
85 /// it represents [WGSL Size](https://gpuweb.github.io/gpuweb/wgsl/#alignment-and-size)
86 /// (equivalent to [`ShaderSize::SHADER_SIZE`])
87 ///
88 /// For
89 /// [WGSL runtime-sized arrays](https://gpuweb.github.io/gpuweb/wgsl/#runtime-sized) and
90 /// [WGSL structs containing runtime-sized arrays](https://gpuweb.github.io/gpuweb/wgsl/#struct-types)
91 /// (non fixed-footprint types)
92 /// this will be calculated by assuming the array has one element
93 #[inline]
94 fn min_size() -> NonZeroU64 {
95 Self::METADATA.min_size().0
96 }
97
98 /// Returns the size of `Self` at runtime
99 ///
100 /// For [WGSL fixed-footprint types](https://gpuweb.github.io/gpuweb/wgsl/#fixed-footprint-types)
101 /// it's equivalent to [`Self::min_size`] and [`ShaderSize::SHADER_SIZE`]
102 #[inline]
103 fn size(&self) -> NonZeroU64 {
104 Self::METADATA.min_size().0
105 }
106
107 #[doc(hidden)]
108 const UNIFORM_COMPAT_ASSERT: fn() = || {};
109
110 /// Asserts that `Self` meets the requirements of the
111 /// [uniform address space restrictions on stored values](https://gpuweb.github.io/gpuweb/wgsl/#address-spaces-uniform) and the
112 /// [uniform address space layout constraints](https://gpuweb.github.io/gpuweb/wgsl/#address-space-layout-constraints)
113 ///
114 /// # Examples
115 ///
116 /// ## Array
117 ///
118 /// Will panic since runtime-sized arrays are not compatible with the
119 /// uniform address space restrictions on stored values
120 ///
121 /// ```should_panic
122 /// # use crate::encase::ShaderType;
123 /// <Vec<mint::Vector4<f32>>>::assert_uniform_compat();
124 /// ```
125 ///
126 /// Will panic since the stride is 4 bytes
127 ///
128 /// ```should_panic
129 /// # use crate::encase::ShaderType;
130 /// <[f32; 2]>::assert_uniform_compat();
131 /// ```
132 ///
133 /// Will not panic since the stride is 16 bytes
134 ///
135 /// ```
136 /// # use crate::encase::ShaderType;
137 /// # use mint;
138 /// <[mint::Vector4<f32>; 2]>::assert_uniform_compat();
139 /// ```
140 ///
141 /// ## Struct
142 ///
143 /// Will panic since runtime-sized arrays are not compatible with the
144 /// uniform address space restrictions on stored values
145 ///
146 /// ```should_panic
147 /// # use crate::encase::ShaderType;
148 /// # use mint;
149 /// #[derive(ShaderType)]
150 /// struct Invalid {
151 /// #[size(runtime)]
152 /// vec: Vec<mint::Vector4<f32>>
153 /// }
154 /// Invalid::assert_uniform_compat();
155 /// ```
156 ///
157 /// Will panic since the inner struct's size must be a multiple of 16
158 ///
159 /// ```should_panic
160 /// # use crate::encase::ShaderType;
161 /// #[derive(ShaderType)]
162 /// struct S {
163 /// x: f32,
164 /// }
165 ///
166 /// #[derive(ShaderType)]
167 /// struct Invalid {
168 /// a: f32,
169 /// b: S, // offset between fields 'a' and 'b' must be at least 16 (currently: 4)
170 /// }
171 /// Invalid::assert_uniform_compat();
172 /// ```
173 ///
174 /// Will not panic (fixed via align attribute)
175 ///
176 /// ```
177 /// # use crate::encase::ShaderType;
178 /// # #[derive(ShaderType)]
179 /// # struct S {
180 /// # x: f32,
181 /// # }
182 /// #[derive(ShaderType)]
183 /// struct Valid {
184 /// a: f32,
185 /// #[align(16)]
186 /// b: S,
187 /// }
188 /// Valid::assert_uniform_compat();
189 /// ```
190 ///
191 /// Will not panic (fixed via size attribute)
192 ///
193 /// ```
194 /// # use crate::encase::ShaderType;
195 /// # #[derive(ShaderType)]
196 /// # struct S {
197 /// # x: f32,
198 /// # }
199 /// #[derive(ShaderType)]
200 /// struct Valid {
201 /// #[size(16)]
202 /// a: f32,
203 /// b: S,
204 /// }
205 /// Valid::assert_uniform_compat();
206 /// ```
207 #[inline]
208 fn assert_uniform_compat() {
209 Self::UNIFORM_COMPAT_ASSERT();
210 }
211
212 // fn assert_can_write_into()
213 // where
214 // Self: WriteInto,
215 // {
216 // }
217
218 // fn assert_can_read_from()
219 // where
220 // Self: ReadFrom,
221 // {
222 // }
223
224 // fn assert_can_create_from()
225 // where
226 // Self: CreateFrom,
227 // {
228 // }
229}
230
231/// Trait implemented for all [WGSL fixed-footprint types](https://gpuweb.github.io/gpuweb/wgsl/#fixed-footprint-types)
232pub trait ShaderSize: ShaderType {
233 /// Represents [WGSL Size](https://gpuweb.github.io/gpuweb/wgsl/#alignment-and-size) (equivalent to [`ShaderType::min_size`])
234 const SHADER_SIZE: NonZeroU64 = Self::METADATA.min_size().0;
235}
236
237/// Trait implemented for
238/// [WGSL runtime-sized arrays](https://gpuweb.github.io/gpuweb/wgsl/#runtime-sized) and
239/// [WGSL structs containing runtime-sized arrays](https://gpuweb.github.io/gpuweb/wgsl/#struct-types)
240/// (non fixed-footprint types)
241pub trait CalculateSizeFor {
242 /// Returns the size of `Self` assuming the (contained) runtime-sized array has `nr_of_el` elements
243 fn calculate_size_for(nr_of_el: u64) -> NonZeroU64;
244}
245
246#[allow(clippy::len_without_is_empty)]
247pub trait RuntimeSizedArray {
248 fn len(&self) -> usize;
249}
250
251pub trait WriteInto {
252 fn write_into<B>(&self, writer: &mut Writer<B>)
253 where
254 B: BufferMut;
255}
256
257pub trait ReadFrom {
258 fn read_from<B>(&mut self, reader: &mut Reader<B>)
259 where
260 B: BufferRef;
261}
262
263pub trait CreateFrom: Sized {
264 fn create_from<B>(reader: &mut Reader<B>) -> Self
265 where
266 B: BufferRef;
267}