@@ -43,74 +43,126 @@ unsafe fn buffer_store_intrinsic<T>(
43
43
. write ( value) ;
44
44
}
45
45
46
- /// `ByteAddressableBuffer` is an untyped blob of data, allowing loads and stores of arbitrary
47
- /// basic data types at arbitrary indices. However, all data must be aligned to size 4, each
48
- /// element within the data (e.g. struct fields) must have a size and alignment of a multiple of 4,
49
- /// and the `byte_index` passed to load and store must be a multiple of 4 (`byte_index` will be
50
- /// rounded down to the nearest multiple of 4). So, it's not technically a *byte* addressable
51
- /// buffer, but rather a *word* buffer, but this naming and behavior was inherited from HLSL (where
52
- /// it's UB to pass in an index not a multiple of 4).
46
+ /// `ByteAddressableBuffer` is a read-only untyped blob of data, allowing loads
47
+ /// of arbitrary basic data types at arbitrary indices. See
48
+ /// [`MutByteAddressableBuffer`] for a writeable variant.
49
+ ///
50
+ /// # Alignment
51
+ /// All data must be aligned to size 4, each element within the data (e.g.
52
+ /// struct fields) must have a size and alignment of a multiple of 4, and the
53
+ /// `byte_index` passed to load and store must be a multiple of 4. Technically
54
+ /// it's not a *byte* addressable buffer, but rather a *word* buffer, but this
55
+ /// naming and behavior was inherited from HLSL (where it's UB to pass in an
56
+ /// index not a multiple of 4).
57
+ ///
58
+ /// # Safety
59
+ /// Using these functions allows reading a different type from the buffer than
60
+ /// was originally written (by [`MutByteAddressableBuffer`] or the host API),
61
+ /// allowing all sorts of safety guarantees to be bypassed (effectively a
62
+ /// transmute).
53
63
#[ repr( transparent) ]
54
64
pub struct ByteAddressableBuffer < ' a > {
55
65
/// The underlying array of bytes, able to be directly accessed.
56
- pub data : & ' a mut [ u32 ] ,
66
+ pub data : & ' a [ u32 ] ,
57
67
}
58
68
59
69
impl < ' a > ByteAddressableBuffer < ' a > {
70
+ /// Creates a `ByteAddressableBuffer` from the untyped blob of data.
71
+ #[ inline]
72
+ pub fn new ( data : & ' a [ u32 ] ) -> Self {
73
+ Self { data }
74
+ }
75
+
76
+ /// Loads an arbitrary type from the buffer. `byte_index` must be a
77
+ /// multiple of 4.
78
+ ///
79
+ /// # Safety
80
+ /// See [`Self`].
81
+ pub unsafe fn load < T > ( & self , byte_index : u32 ) -> T {
82
+ if byte_index % 4 != 0 {
83
+ panic ! ( "`byte_index` should be a multiple of 4" ) ;
84
+ }
85
+ if byte_index + mem:: size_of :: < T > ( ) as u32 > self . data . len ( ) as u32 {
86
+ panic ! (
87
+ "index out of bounds: the len is {} but the `byte_index` is {}" ,
88
+ self . data. len( ) ,
89
+ byte_index
90
+ ) ;
91
+ }
92
+ buffer_load_intrinsic ( self . data , byte_index)
93
+ }
94
+
95
+ /// Loads an arbitrary type from the buffer. `byte_index` must be a
96
+ /// multiple of 4.
97
+ ///
98
+ /// # Safety
99
+ /// See [`Self`]. Additionally, bounds or alignment checking is not performed.
100
+ pub unsafe fn load_unchecked < T > ( & self , byte_index : u32 ) -> T {
101
+ buffer_load_intrinsic ( self . data , byte_index)
102
+ }
103
+ }
104
+
105
+ /// `MutByteAddressableBuffer` is a mutable untyped blob of data, allowing
106
+ /// loads and stores of arbitrary basic data types at arbitrary indices. See
107
+ /// [`ByteAddressableBuffer`] for details.
108
+ #[ repr( transparent) ]
109
+ pub struct MutByteAddressableBuffer < ' a > {
110
+ /// The underlying array of bytes, able to be directly accessed.
111
+ pub data : & ' a mut [ u32 ] ,
112
+ }
113
+
114
+ impl < ' a > MutByteAddressableBuffer < ' a > {
60
115
/// Creates a `ByteAddressableBuffer` from the untyped blob of data.
61
116
#[ inline]
62
117
pub fn new ( data : & ' a mut [ u32 ] ) -> Self {
63
118
Self { data }
64
119
}
65
120
66
- /// Loads an arbitrary type from the buffer. `byte_index` must be a multiple of 4, otherwise,
67
- /// it will get silently rounded down to the nearest multiple of 4.
121
+ /// Loads an arbitrary type from the buffer. `byte_index` must be a
122
+ /// multiple of 4.
68
123
///
69
124
/// # Safety
70
- /// This function allows writing a type to an untyped buffer, then reading a different type
71
- /// from the same buffer, allowing all sorts of safety guarantees to be bypassed (effectively a
72
- /// transmute)
125
+ /// See [`Self`].
73
126
pub unsafe fn load < T > ( & self , byte_index : u32 ) -> T {
127
+ if byte_index % 4 != 0 {
128
+ panic ! ( "`byte_index` should be a multiple of 4" ) ;
129
+ }
74
130
if byte_index + mem:: size_of :: < T > ( ) as u32 > self . data . len ( ) as u32 {
75
- panic ! ( "Index out of range" ) ;
131
+ panic ! (
132
+ "index out of bounds: the len is {} but the `byte_index` is {}" ,
133
+ self . data. len( ) ,
134
+ byte_index
135
+ ) ;
76
136
}
77
137
buffer_load_intrinsic ( self . data , byte_index)
78
138
}
79
139
80
- /// Loads an arbitrary type from the buffer. `byte_index` must be a multiple of 4, otherwise,
81
- /// it will get silently rounded down to the nearest multiple of 4. Bounds checking is not
82
- /// performed.
140
+ /// Loads an arbitrary type from the buffer. `byte_index` must be a
141
+ /// multiple of 4.
83
142
///
84
143
/// # Safety
85
- /// This function allows writing a type to an untyped buffer, then reading a different type
86
- /// from the same buffer, allowing all sorts of safety guarantees to be bypassed (effectively a
87
- /// transmute). Additionally, bounds checking is not performed.
144
+ /// See [`Self`]. Additionally, bounds or alignment checking is not performed.
88
145
pub unsafe fn load_unchecked < T > ( & self , byte_index : u32 ) -> T {
89
146
buffer_load_intrinsic ( self . data , byte_index)
90
147
}
91
148
92
- /// Stores an arbitrary type int the buffer. `byte_index` must be a multiple of 4, otherwise,
93
- /// it will get silently rounded down to the nearest multiple of 4.
149
+ /// Stores an arbitrary type into the buffer. `byte_index` must be a
150
+ /// multiple of 4.
94
151
///
95
152
/// # Safety
96
- /// This function allows writing a type to an untyped buffer, then reading a different type
97
- /// from the same buffer, allowing all sorts of safety guarantees to be bypassed (effectively a
98
- /// transmute)
153
+ /// See [`Self`].
99
154
pub unsafe fn store < T > ( & mut self , byte_index : u32 , value : T ) {
100
155
if byte_index + mem:: size_of :: < T > ( ) as u32 > self . data . len ( ) as u32 {
101
156
panic ! ( "Index out of range" ) ;
102
157
}
103
158
buffer_store_intrinsic ( self . data , byte_index, value) ;
104
159
}
105
160
106
- /// Stores an arbitrary type int the buffer. `byte_index` must be a multiple of 4, otherwise,
107
- /// it will get silently rounded down to the nearest multiple of 4. Bounds checking is not
108
- /// performed.
161
+ /// Stores an arbitrary type into the buffer. `byte_index` must be a
162
+ /// multiple of 4.
109
163
///
110
164
/// # Safety
111
- /// This function allows writing a type to an untyped buffer, then reading a different type
112
- /// from the same buffer, allowing all sorts of safety guarantees to be bypassed (effectively a
113
- /// transmute). Additionally, bounds checking is not performed.
165
+ /// See [`Self`]. Additionally, bounds or alignment checking is not performed.
114
166
pub unsafe fn store_unchecked < T > ( & mut self , byte_index : u32 , value : T ) {
115
167
buffer_store_intrinsic ( self . data , byte_index, value) ;
116
168
}
0 commit comments