@@ -28,6 +28,43 @@ use super::{
2828 RenderContext ,
2929} ;
3030
31+ /// Marker trait for types that are safe to reinterpret as raw bytes.
32+ ///
33+ /// This trait is required by `Buffer::write_value`, `Buffer::write_slice`, and
34+ /// `BufferBuilder::build` because those APIs upload the in-memory representation
35+ /// of a value to the GPU.
36+ ///
37+ /// # Safety
38+ /// Types implementing `PlainOldData` MUST satisfy all of the following:
39+ /// - Every byte of the value is initialized (including any padding bytes).
40+ /// - The type has no pointers or references that would be invalidated by a
41+ /// raw byte copy.
42+ /// - The type's byte representation is stable for GPU consumption. Prefer
43+ /// `#[repr(C)]` or `#[repr(transparent)]`.
44+ ///
45+ /// Implementing this trait incorrectly can cause undefined behavior.
46+ pub unsafe trait PlainOldData : Copy { }
47+
48+ unsafe impl PlainOldData for u8 { }
49+ unsafe impl PlainOldData for i8 { }
50+ unsafe impl PlainOldData for u16 { }
51+ unsafe impl PlainOldData for i16 { }
52+ unsafe impl PlainOldData for u32 { }
53+ unsafe impl PlainOldData for i32 { }
54+ unsafe impl PlainOldData for u64 { }
55+ unsafe impl PlainOldData for i64 { }
56+ unsafe impl PlainOldData for u128 { }
57+ unsafe impl PlainOldData for i128 { }
58+ unsafe impl PlainOldData for usize { }
59+ unsafe impl PlainOldData for isize { }
60+ unsafe impl PlainOldData for f32 { }
61+ unsafe impl PlainOldData for f64 { }
62+ unsafe impl PlainOldData for bool { }
63+ unsafe impl PlainOldData for char { }
64+ unsafe impl < T : PlainOldData , const N : usize > PlainOldData for [ T ; N ] { }
65+
66+ unsafe impl PlainOldData for super :: vertex:: Vertex { }
67+
3168/// High‑level classification for buffers created by the engine.
3269#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
3370///
@@ -140,8 +177,8 @@ impl Buffer {
140177
141178 /// Write a single plain-old-data value into this buffer at the specified
142179 /// byte offset. This is intended for updating uniform buffer contents from
143- /// the CPU. The `data` type must be trivially copyable .
144- pub fn write_value < T : Copy > ( & self , gpu : & Gpu , offset : u64 , data : & T ) {
180+ /// the CPU. The `data` type must implement `PlainOldData` .
181+ pub fn write_value < T : PlainOldData > ( & self , gpu : & Gpu , offset : u64 , data : & T ) {
145182 let bytes = value_as_bytes ( data) ;
146183 self . write_bytes ( gpu, offset, bytes) ;
147184 }
@@ -165,7 +202,8 @@ impl Buffer {
165202 ///
166203 /// This is intended for uploading arrays of vertices, indices, instance
167204 /// data, or uniform blocks. The `T` type MUST be plain-old-data (POD) and
168- /// safely representable as bytes.
205+ /// safely representable as bytes. This is enforced by requiring `T` to
206+ /// implement `PlainOldData`.
169207 ///
170208 /// Example
171209 /// ```rust,ignore
@@ -174,7 +212,7 @@ impl Buffer {
174212 /// .write_slice(render_context.gpu(), 0, &transforms)
175213 /// .unwrap();
176214 /// ```
177- pub fn write_slice < T : Copy > (
215+ pub fn write_slice < T : PlainOldData > (
178216 & self ,
179217 gpu : & Gpu ,
180218 offset : u64 ,
@@ -186,7 +224,7 @@ impl Buffer {
186224 }
187225}
188226
189- fn value_as_bytes < T : Copy > ( data : & T ) -> & [ u8 ] {
227+ fn value_as_bytes < T : PlainOldData > ( data : & T ) -> & [ u8 ] {
190228 let bytes = unsafe {
191229 std:: slice:: from_raw_parts (
192230 ( data as * const T ) as * const u8 ,
@@ -206,7 +244,7 @@ fn checked_byte_len(
206244 return Ok ( byte_len) ;
207245}
208246
209- fn slice_as_bytes < T : Copy > ( data : & [ T ] ) -> Result < & [ u8 ] , & ' static str > {
247+ fn slice_as_bytes < T : PlainOldData > ( data : & [ T ] ) -> Result < & [ u8 ] , & ' static str > {
210248 let element_size = std:: mem:: size_of :: < T > ( ) ;
211249 let byte_len = checked_byte_len ( element_size, data. len ( ) ) ?;
212250
@@ -238,7 +276,7 @@ pub struct UniformBuffer<T> {
238276 _phantom : core:: marker:: PhantomData < T > ,
239277}
240278
241- impl < T : Copy > UniformBuffer < T > {
279+ impl < T : PlainOldData > UniformBuffer < T > {
242280 /// Create a new uniform buffer initialized with `initial`.
243281 pub fn new (
244282 gpu : & Gpu ,
@@ -349,22 +387,23 @@ impl BufferBuilder {
349387 /// Create a buffer initialized with the provided `data`.
350388 ///
351389 /// Returns an error if the resolved length would be zero.
352- pub fn build < Data : Copy > (
390+ ///
391+ /// The element type MUST implement `PlainOldData` because the engine uploads
392+ /// the in-memory representation to the GPU.
393+ pub fn build < Data : PlainOldData > (
353394 & self ,
354395 gpu : & Gpu ,
355396 data : Vec < Data > ,
356397 ) -> Result < Buffer , & ' static str > {
357398 let element_size = std:: mem:: size_of :: < Data > ( ) ;
358399 let buffer_length = self . resolve_length ( element_size, data. len ( ) ) ?;
400+ let byte_len = checked_byte_len ( element_size, data. len ( ) ) ?;
359401
360402 // SAFETY: Converting data to bytes is safe because its underlying
361- // type, Data, is constrained to Copy and the lifetime of the slice does
362- // not outlive data.
403+ // type, Data, is constrained to PlainOldData and the lifetime of the slice
404+ // does not outlive data.
363405 let bytes = unsafe {
364- std:: slice:: from_raw_parts (
365- data. as_ptr ( ) as * const u8 ,
366- element_size * data. len ( ) ,
367- )
406+ std:: slice:: from_raw_parts ( data. as_ptr ( ) as * const u8 , byte_len)
368407 } ;
369408
370409 let mut builder = platform_buffer:: BufferBuilder :: new ( )
0 commit comments