@@ -24,9 +24,9 @@ use smallvec::SmallVec;
24
24
use bevy_ecs:: prelude:: { Entity , World } ;
25
25
26
26
use crate :: {
27
- add_listener_to_source, Accessed , AddOperation , AnyBuffer , AnyBufferKey , AnyMessageBox , AsAnyBuffer ,
28
- BufferKeyBuilder , Bufferable , Buffered , Builder , Chain , Gate , GateState , Join , Joined ,
29
- OperationError , OperationResult , OperationRoster , Output , UnusedTarget ,
27
+ add_listener_to_source, Accessed , AddOperation , AnyBuffer , AnyBufferKey , AnyMessageBox ,
28
+ AsAnyBuffer , Buffer , BufferKeyBuilder , Bufferable , Buffered , Builder , Chain , Gate , GateState ,
29
+ Join , Joined , OperationError , OperationResult , OperationRoster , Output , UnusedTarget ,
30
30
} ;
31
31
32
32
pub use bevy_impulse_derive:: JoinedValue ;
@@ -92,15 +92,32 @@ impl AddBufferToMap for BufferMap {
92
92
#[ derive( ThisError , Debug , Clone , Default ) ]
93
93
#[ error( "the incoming buffer map is incompatible with the layout" ) ]
94
94
pub struct IncompatibleLayout {
95
- /// Names of buffers that were missing from the incoming buffer map.
95
+ /// Identities of buffers that were missing from the incoming buffer map.
96
96
pub missing_buffers : Vec < BufferIdentifier < ' static > > ,
97
+ /// Identities of buffers in the incoming buffer map which cannot exist in
98
+ /// the target layout.
99
+ pub forbidden_buffers : Vec < BufferIdentifier < ' static > > ,
97
100
/// Buffers whose expected type did not match the received type.
98
101
pub incompatible_buffers : Vec < BufferIncompatibility > ,
99
102
}
100
103
101
104
impl IncompatibleLayout {
102
- /// Check whether a named buffer is compatible with a specialized buffer type,
103
- /// such as `JsonBuffer`.
105
+ /// Convert this into an error if it has any contents inside.
106
+ pub fn as_result ( self ) -> Result < ( ) , Self > {
107
+ if !self . missing_buffers . is_empty ( ) {
108
+ return Err ( self ) ;
109
+ }
110
+
111
+ if !self . incompatible_buffers . is_empty ( ) {
112
+ return Err ( self ) ;
113
+ }
114
+
115
+ Ok ( ( ) )
116
+ }
117
+
118
+ /// Same as [`Self::require_buffer_by_literal`], but can be used with
119
+ /// temporary borrows of a string slice. The string slice will be cloned if
120
+ /// an error message needs to be produced.
104
121
pub fn require_buffer_by_name < BufferType : ' static > (
105
122
& mut self ,
106
123
expected_name : & str ,
@@ -118,20 +135,38 @@ impl IncompatibleLayout {
118
135
} ) ;
119
136
}
120
137
} else {
121
- self . missing_buffers . push ( BufferIdentifier :: Name ( Cow :: Owned ( expected_name. to_owned ( ) ) ) ) ;
138
+ self . missing_buffers
139
+ . push ( BufferIdentifier :: Name ( Cow :: Owned ( expected_name. to_owned ( ) ) ) ) ;
122
140
}
123
141
124
142
Err ( ( ) )
125
143
}
126
144
127
- /// Same as [`Self::require_buffer_by_name`] but more efficient for names
128
- /// given by string literal values.
145
+ /// Check whether a named buffer is compatible with the required buffer type.
129
146
pub fn require_buffer_by_literal < BufferType : ' static > (
130
147
& mut self ,
131
148
expected_name : & ' static str ,
132
149
buffers : & BufferMap ,
133
150
) -> Result < BufferType , ( ) > {
134
- let identifier = BufferIdentifier :: Name ( Cow :: Borrowed ( expected_name) ) ;
151
+ self . require_buffer :: < BufferType > ( BufferIdentifier :: literal_name ( expected_name) , buffers)
152
+ }
153
+
154
+ /// Check whether an indexed buffer is compatible with the required buffer type.
155
+ pub fn require_buffer_by_index < BufferType : ' static > (
156
+ & mut self ,
157
+ expected_index : usize ,
158
+ buffers : & BufferMap ,
159
+ ) -> Result < BufferType , ( ) > {
160
+ self . require_buffer :: < BufferType > ( BufferIdentifier :: Index ( expected_index) , buffers)
161
+ }
162
+
163
+ /// Check whether the buffer associated with the identifier is compatible with
164
+ /// the required buffer type.
165
+ pub fn require_buffer < BufferType : ' static > (
166
+ & mut self ,
167
+ identifier : BufferIdentifier < ' static > ,
168
+ buffers : & BufferMap ,
169
+ ) -> Result < BufferType , ( ) > {
135
170
if let Some ( buffer) = buffers. get ( & identifier) {
136
171
if let Some ( buffer) = buffer. downcast_buffer :: < BufferType > ( ) {
137
172
return Ok ( buffer) ;
@@ -167,22 +202,26 @@ pub struct BufferIncompatibility {
167
202
/// `#[derive(JoinedValue)]` on a struct that you want a join operation to
168
203
/// produce.
169
204
pub trait BufferMapLayout : Sized + Clone + ' static + Send + Sync {
170
- /// Produce a list of the buffers that exist in this layout.
171
- fn buffer_list ( & self ) -> SmallVec < [ AnyBuffer ; 8 ] > ;
172
-
173
205
/// Try to convert a generic [`BufferMap`] into this specific layout.
174
206
fn try_from_buffer_map ( buffers : & BufferMap ) -> Result < Self , IncompatibleLayout > ;
175
207
}
176
208
177
- impl < T : BufferMapLayout > Bufferable for T {
209
+ /// This trait helps auto-generated buffer map structs to implement the Buffered
210
+ /// trait.
211
+ pub trait BufferMapStruct : Sized + Clone + ' static + Send + Sync {
212
+ /// Produce a list of the buffers that exist in this layout.
213
+ fn buffer_list ( & self ) -> SmallVec < [ AnyBuffer ; 8 ] > ;
214
+ }
215
+
216
+ impl < T : BufferMapStruct > Bufferable for T {
178
217
type BufferType = Self ;
179
218
180
219
fn into_buffer ( self , _: & mut Builder ) -> Self :: BufferType {
181
220
self
182
221
}
183
222
}
184
223
185
- impl < T : BufferMapLayout > Buffered for T {
224
+ impl < T : BufferMapStruct > Buffered for T {
186
225
fn verify_scope ( & self , scope : Entity ) {
187
226
for buffer in self . buffer_list ( ) {
188
227
assert_eq ! ( buffer. scope( ) , scope) ;
@@ -285,14 +324,17 @@ pub trait BufferKeyMap: 'static + Send + Sync + Sized + Clone {
285
324
}
286
325
287
326
impl BufferMapLayout for BufferMap {
288
- fn buffer_list ( & self ) -> SmallVec < [ AnyBuffer ; 8 ] > {
289
- self . values ( ) . cloned ( ) . collect ( )
290
- }
291
327
fn try_from_buffer_map ( buffers : & BufferMap ) -> Result < Self , IncompatibleLayout > {
292
328
Ok ( buffers. clone ( ) )
293
329
}
294
330
}
295
331
332
+ impl BufferMapStruct for BufferMap {
333
+ fn buffer_list ( & self ) -> SmallVec < [ AnyBuffer ; 8 ] > {
334
+ self . values ( ) . cloned ( ) . collect ( )
335
+ }
336
+ }
337
+
296
338
impl Joined for BufferMap {
297
339
type Item = HashMap < BufferIdentifier < ' static > , AnyMessageBox > ;
298
340
@@ -351,9 +393,49 @@ impl Accessed for BufferMap {
351
393
}
352
394
}
353
395
396
+ impl < T : ' static + Send + Sync > JoinedValue for Vec < T > {
397
+ type Buffers = Vec < Buffer < T > > ;
398
+ }
399
+
400
+ impl < B : ' static + Send + Sync + AsAnyBuffer + Clone > BufferMapLayout for Vec < B > {
401
+ fn try_from_buffer_map ( buffers : & BufferMap ) -> Result < Self , IncompatibleLayout > {
402
+ let mut downcast_buffers = Vec :: new ( ) ;
403
+ let mut compatibility = IncompatibleLayout :: default ( ) ;
404
+ for i in 0 ..buffers. len ( ) {
405
+ if let Ok ( downcast) = compatibility. require_buffer_by_index :: < B > ( i, buffers) {
406
+ downcast_buffers. push ( downcast) ;
407
+ }
408
+ }
409
+
410
+ compatibility. as_result ( ) ?;
411
+ Ok ( downcast_buffers)
412
+ }
413
+ }
414
+
415
+ impl < T : ' static + Send + Sync , const N : usize > JoinedValue for SmallVec < [ T ; N ] > {
416
+ type Buffers = SmallVec < [ Buffer < T > ; N ] > ;
417
+ }
418
+
419
+ impl < B : ' static + Send + Sync + AsAnyBuffer + Clone , const N : usize > BufferMapLayout
420
+ for SmallVec < [ B ; N ] >
421
+ {
422
+ fn try_from_buffer_map ( buffers : & BufferMap ) -> Result < Self , IncompatibleLayout > {
423
+ let mut downcast_buffers = SmallVec :: new ( ) ;
424
+ let mut compatibility = IncompatibleLayout :: default ( ) ;
425
+ for i in 0 ..buffers. len ( ) {
426
+ if let Ok ( downcast) = compatibility. require_buffer_by_index :: < B > ( i, buffers) {
427
+ downcast_buffers. push ( downcast) ;
428
+ }
429
+ }
430
+
431
+ compatibility. as_result ( ) ?;
432
+ Ok ( downcast_buffers)
433
+ }
434
+ }
435
+
354
436
#[ cfg( test) ]
355
437
mod tests {
356
- use crate :: { prelude:: * , testing:: * , BufferMap , AddBufferToMap } ;
438
+ use crate :: { prelude:: * , testing:: * , AddBufferToMap , BufferMap } ;
357
439
358
440
#[ derive( JoinedValue ) ]
359
441
struct TestJoinedValue < T : Send + Sync + ' static + Clone > {
0 commit comments