@@ -24,9 +24,9 @@ use smallvec::SmallVec;
2424use bevy_ecs:: prelude:: { Entity , World } ;
2525
2626use 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 ,
3030} ;
3131
3232pub use bevy_impulse_derive:: JoinedValue ;
@@ -92,15 +92,32 @@ impl AddBufferToMap for BufferMap {
9292#[ derive( ThisError , Debug , Clone , Default ) ]
9393#[ error( "the incoming buffer map is incompatible with the layout" ) ]
9494pub 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.
9696 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 > > ,
97100 /// Buffers whose expected type did not match the received type.
98101 pub incompatible_buffers : Vec < BufferIncompatibility > ,
99102}
100103
101104impl 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.
104121 pub fn require_buffer_by_name < BufferType : ' static > (
105122 & mut self ,
106123 expected_name : & str ,
@@ -118,20 +135,38 @@ impl IncompatibleLayout {
118135 } ) ;
119136 }
120137 } 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 ( ) ) ) ) ;
122140 }
123141
124142 Err ( ( ) )
125143 }
126144
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.
129146 pub fn require_buffer_by_literal < BufferType : ' static > (
130147 & mut self ,
131148 expected_name : & ' static str ,
132149 buffers : & BufferMap ,
133150 ) -> 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 , ( ) > {
135170 if let Some ( buffer) = buffers. get ( & identifier) {
136171 if let Some ( buffer) = buffer. downcast_buffer :: < BufferType > ( ) {
137172 return Ok ( buffer) ;
@@ -167,22 +202,26 @@ pub struct BufferIncompatibility {
167202/// `#[derive(JoinedValue)]` on a struct that you want a join operation to
168203/// produce.
169204pub 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-
173205 /// Try to convert a generic [`BufferMap`] into this specific layout.
174206 fn try_from_buffer_map ( buffers : & BufferMap ) -> Result < Self , IncompatibleLayout > ;
175207}
176208
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 {
178217 type BufferType = Self ;
179218
180219 fn into_buffer ( self , _: & mut Builder ) -> Self :: BufferType {
181220 self
182221 }
183222}
184223
185- impl < T : BufferMapLayout > Buffered for T {
224+ impl < T : BufferMapStruct > Buffered for T {
186225 fn verify_scope ( & self , scope : Entity ) {
187226 for buffer in self . buffer_list ( ) {
188227 assert_eq ! ( buffer. scope( ) , scope) ;
@@ -285,14 +324,17 @@ pub trait BufferKeyMap: 'static + Send + Sync + Sized + Clone {
285324}
286325
287326impl BufferMapLayout for BufferMap {
288- fn buffer_list ( & self ) -> SmallVec < [ AnyBuffer ; 8 ] > {
289- self . values ( ) . cloned ( ) . collect ( )
290- }
291327 fn try_from_buffer_map ( buffers : & BufferMap ) -> Result < Self , IncompatibleLayout > {
292328 Ok ( buffers. clone ( ) )
293329 }
294330}
295331
332+ impl BufferMapStruct for BufferMap {
333+ fn buffer_list ( & self ) -> SmallVec < [ AnyBuffer ; 8 ] > {
334+ self . values ( ) . cloned ( ) . collect ( )
335+ }
336+ }
337+
296338impl Joined for BufferMap {
297339 type Item = HashMap < BufferIdentifier < ' static > , AnyMessageBox > ;
298340
@@ -351,9 +393,49 @@ impl Accessed for BufferMap {
351393 }
352394}
353395
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+
354436#[ cfg( test) ]
355437mod tests {
356- use crate :: { prelude:: * , testing:: * , BufferMap , AddBufferToMap } ;
438+ use crate :: { prelude:: * , testing:: * , AddBufferToMap , BufferMap } ;
357439
358440 #[ derive( JoinedValue ) ]
359441 struct TestJoinedValue < T : Send + Sync + ' static + Clone > {
0 commit comments