@@ -4,31 +4,31 @@ use crate::{
44} ;
55
66/// The data storage type that is being accessed.
7- #[ derive( Clone , Copy ) ]
7+ #[ derive( Clone , Copy , Debug ) ]
88pub enum EcsAccessType {
9- /// Accesses [`Component`] data
9+ /// Accesses [`Component`](crate::prelude::Component) data
1010 Component ( EcsAccessLevel ) ,
11- /// Accesses [`Resource`] data
11+ /// Accesses [`Resource`](crate::prelude::Resource) data
1212 Resource ( ResourceAccessLevel ) ,
1313}
1414
1515/// The way the data will be accessed and whether we take access on all the components on
1616/// an entity or just one component.
17- #[ derive( Clone , Copy ) ]
17+ #[ derive( Clone , Copy , Debug ) ]
1818pub enum EcsAccessLevel {
19- /// Reads [`Component`] with [`ComponentId`]
19+ /// Reads [`Component`](crate::prelude::Component) with [`ComponentId`]
2020 Read ( ComponentId ) ,
21- /// Writes [`Component`] with [`ComponentId`]
21+ /// Writes [`Component`](crate::prelude::Component) with [`ComponentId`]
2222 Write ( ComponentId ) ,
23- /// Potentially reads all [`Component`]'s in the [`World`]
23+ /// Potentially reads all [`Component`](crate::prelude::Component) 's in the [`World`](crate::prelude::World)
2424 ReadAll ,
25- /// Potentially writes all [`Component`]'s in the [`World`]
25+ /// Potentially writes all [`Component`](crate::prelude::Component) 's in the [`World`](crate::prelude::World)
2626 WriteAll ,
27- /// [`FilteredEntityRef`] captures it's access at the `SystemParam` level, so will
28- /// not conflict with other `QueryData` in the same Query
27+ /// [`FilteredEntityRef`](crate::world::FilteredEntityRef) captures it's access at the `SystemParam` level, so will
28+ /// not conflict with other [ `QueryData`] in the same Query
2929 FilteredReadAll ,
30- /// [`FilteredEntityMut`] captures it's access at the `SystemParam` level, so will
31- /// not conflict with other `QueryData` in the same Query
30+ /// [`FilteredEntityMut`](crate::world::FilteredEntityMut) captures it's access at the `SystemParam` level, so will
31+ /// not conflict with other [ `QueryData`] in the same Query
3232 FilteredWriteAll ,
3333 /// Potentially reads all [`Components`]'s except [`ComponentId`]
3434 ReadAllExcept {
@@ -47,7 +47,7 @@ pub enum EcsAccessLevel {
4747}
4848
4949/// Access level needed by [`QueryData`] fetch to the resource.
50- #[ derive( Copy , Clone ) ]
50+ #[ derive( Copy , Clone , Debug ) ]
5151pub enum ResourceAccessLevel {
5252 /// Reads the resource with [`ComponentId`]
5353 Read ( ComponentId ) ,
@@ -93,7 +93,7 @@ impl EcsAccessType {
9393 }
9494 }
9595
96- /// Returns true if the access between `self` and `other` do not conflict.
96+ /// See [`AccessCompatible`] for more info
9797 pub fn is_compatible ( & self , other : Self ) -> AccessCompatible {
9898 use EcsAccessLevel :: * ;
9999 use EcsAccessType :: * ;
@@ -206,21 +206,52 @@ impl EcsAccessType {
206206 }
207207}
208208
209+ /// Error returned from [`has_conflicts`].
210+ #[ derive( Clone , Copy , Debug ) ]
211+ pub enum AccessError {
212+ ComponentNotRegistered ,
213+ Conflict ( EcsAccessType , EcsAccessType ) ,
214+ EntityDoesNotMatch ,
215+ }
216+
217+ impl core:: error:: Error for AccessError { }
218+
219+ impl core:: fmt:: Display for AccessError {
220+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
221+ match * self {
222+ AccessError :: ComponentNotRegistered => {
223+ write ! (
224+ f,
225+ "At least one component in Q was not registered in world.
226+ Consider calling `World::register_component`"
227+ )
228+ }
229+ AccessError :: Conflict ( ecs_access, ecs_access1) => {
230+ write ! ( f, "Conflict between {ecs_access:?} and {ecs_access1:?}" )
231+ }
232+ AccessError :: EntityDoesNotMatch => {
233+ write ! ( f, "Entity does not match Q" )
234+ }
235+ }
236+ }
237+ }
238+
209239/// Check if `Q` has any internal conflicts.
210- pub fn has_conflicts < Q : QueryData > ( components : & Components ) -> bool {
240+ pub fn has_conflicts < Q : QueryData > ( components : & Components ) -> Result < ( ) , AccessError > {
211241 let mut index_outer = 0 ;
212242 for ( i, access) in Q :: iter_access ( components, & mut index_outer) . enumerate ( ) {
213243 let mut index_inner = 0 ;
214244 let mut except_index = None ;
215245 let mut except_compatible = false ;
246+ let mut last_access = None ;
216247 for ( j, access_other) in Q :: iter_access ( components, & mut index_inner) . enumerate ( ) {
248+ last_access = access_other;
217249 // don't check for conflicts when the access is the same access
218250 if i == j {
219251 continue ;
220252 }
221253 let ( Some ( access) , Some ( access_other) ) = ( access, access_other) else {
222- // A component wasn't registered
223- return true ;
254+ return Err ( AccessError :: ComponentNotRegistered ) ;
224255 } ;
225256
226257 // if we're in an except sequence, check if the sequence has ended
@@ -233,7 +264,7 @@ pub fn has_conflicts<Q: QueryData>(components: &Components) -> bool {
233264
234265 if sequence_ended {
235266 if !except_compatible {
236- return true ;
267+ return Err ( AccessError :: Conflict ( access , access_other ) ) ;
237268 }
238269 except_compatible = false ;
239270 except_index = None ;
@@ -248,18 +279,20 @@ pub fn has_conflicts<Q: QueryData>(components: &Components) -> bool {
248279 except_index = Some ( index) ;
249280 except_compatible = true ;
250281 } ,
251- AccessCompatible :: Conflicts => return true ,
282+ AccessCompatible :: Conflicts => return Err ( AccessError :: Conflict ( access , access_other ) ) ,
252283 AccessCompatible :: ConflictsExceptSecond ( index) => {
253284 except_index = Some ( index) ;
254285 }
255286 }
256287 }
257288
258289 if except_index. is_some ( ) && !except_compatible {
259- return true ;
290+ if let ( Some ( access) , Some ( access_other) ) = ( access, last_access) {
291+ return Err ( AccessError :: Conflict ( access, access_other) ) ;
292+ }
260293 }
261294 }
262- false
295+ Ok ( ( ) )
263296}
264297
265298#[ cfg( test) ]
@@ -284,14 +317,23 @@ mod tests {
284317 let c = world. components ( ) ;
285318
286319 // Compatible
287- assert ! ( ! has_conflicts:: <& mut C1 >( c) ) ;
288- assert ! ( ! has_conflicts:: <& C1 >( c) ) ;
289- assert ! ( ! has_conflicts:: <( & C1 , & C1 ) >( c) ) ;
320+ assert ! ( has_conflicts:: <& mut C1 >( c) . is_ok ( ) ) ;
321+ assert ! ( has_conflicts:: <& C1 >( c) . is_ok ( ) ) ;
322+ assert ! ( has_conflicts:: <( & C1 , & C1 ) >( c) . is_ok ( ) ) ;
290323
291324 // Conflicts
292- assert ! ( has_conflicts:: <( & C1 , & mut C1 ) >( c) ) ;
293- assert ! ( has_conflicts:: <( & mut C1 , & C1 ) >( c) ) ;
294- assert ! ( has_conflicts:: <( & mut C1 , & mut C1 ) >( c) ) ;
325+ assert ! ( matches!(
326+ has_conflicts:: <( & C1 , & mut C1 ) >( c) ,
327+ Err ( AccessError :: Conflict ( _, _) )
328+ ) ) ;
329+ assert ! ( matches!(
330+ has_conflicts:: <( & mut C1 , & C1 ) >( c) ,
331+ Err ( AccessError :: Conflict ( _, _) )
332+ ) ) ;
333+ assert ! ( matches!(
334+ has_conflicts:: <( & mut C1 , & mut C1 ) >( c) ,
335+ Err ( AccessError :: Conflict ( _, _) )
336+ ) ) ;
295337 }
296338
297339 #[ test]
@@ -302,19 +344,43 @@ mod tests {
302344 let c = world. components ( ) ;
303345
304346 // Compatible
305- assert ! ( ! has_conflicts:: <( EntityRef , & C1 ) >( c) ) ;
306- assert ! ( ! has_conflicts:: <( & C1 , EntityRef ) >( c) ) ;
307- assert ! ( ! has_conflicts:: <( EntityRef , EntityRef ) >( c) ) ;
347+ assert ! ( has_conflicts:: <( EntityRef , & C1 ) >( c) . is_ok ( ) ) ;
348+ assert ! ( has_conflicts:: <( & C1 , EntityRef ) >( c) . is_ok ( ) ) ;
349+ assert ! ( has_conflicts:: <( EntityRef , EntityRef ) >( c) . is_ok ( ) ) ;
308350
309351 // Conflicts
310- assert ! ( has_conflicts:: <( EntityRef , & mut C1 ) >( c) ) ;
311- assert ! ( has_conflicts:: <( & mut C1 , EntityRef ) >( c) ) ;
312- assert ! ( has_conflicts:: <( EntityMut , & C1 ) >( c) ) ;
313- assert ! ( has_conflicts:: <( & C1 , EntityMut ) >( c) ) ;
314- assert ! ( has_conflicts:: <( EntityMut , & mut C1 ) >( c) ) ;
315- assert ! ( has_conflicts:: <( & mut C1 , EntityMut ) >( c) ) ;
316- assert ! ( has_conflicts:: <( EntityMut , EntityRef ) >( c) ) ;
317- assert ! ( has_conflicts:: <( EntityRef , EntityMut ) >( c) ) ;
352+ assert ! ( matches!(
353+ has_conflicts:: <( EntityRef , & mut C1 ) >( c) ,
354+ Err ( AccessError :: Conflict ( _, _) )
355+ ) ) ;
356+ assert ! ( matches!(
357+ has_conflicts:: <( & mut C1 , EntityRef ) >( c) ,
358+ Err ( AccessError :: Conflict ( _, _) )
359+ ) ) ;
360+ assert ! ( matches!(
361+ has_conflicts:: <( EntityMut , & C1 ) >( c) ,
362+ Err ( AccessError :: Conflict ( _, _) )
363+ ) ) ;
364+ assert ! ( matches!(
365+ has_conflicts:: <( & C1 , EntityMut ) >( c) ,
366+ Err ( AccessError :: Conflict ( _, _) )
367+ ) ) ;
368+ assert ! ( matches!(
369+ has_conflicts:: <( EntityMut , & mut C1 ) >( c) ,
370+ Err ( AccessError :: Conflict ( _, _) )
371+ ) ) ;
372+ assert ! ( matches!(
373+ has_conflicts:: <( & mut C1 , EntityMut ) >( c) ,
374+ Err ( AccessError :: Conflict ( _, _) )
375+ ) ) ;
376+ assert ! ( matches!(
377+ has_conflicts:: <( EntityMut , EntityRef ) >( c) ,
378+ Err ( AccessError :: Conflict ( _, _) )
379+ ) ) ;
380+ assert ! ( matches!(
381+ has_conflicts:: <( EntityRef , EntityMut ) >( c) ,
382+ Err ( AccessError :: Conflict ( _, _) )
383+ ) ) ;
318384 }
319385
320386 #[ test]
@@ -325,30 +391,24 @@ mod tests {
325391 let c = world. components ( ) ;
326392
327393 // Compatible
328- assert ! ( !has_conflicts:: <( EntityRefExcept <C1 >, & mut C1 ) >( c) ) ;
329- assert ! ( !has_conflicts:: <( & mut C1 , EntityRefExcept <C1 >) >( c) ) ;
330- assert ! ( !has_conflicts:: <( & C2 , EntityRefExcept <C1 >) >( c) ) ;
331- assert ! ( !has_conflicts:: <( & mut C1 , EntityRefExcept <( C1 , C2 ) >, ) >( c) ) ;
332- assert ! ( !has_conflicts:: <( EntityRefExcept <( C1 , C2 ) >, & mut C1 , ) >( c) ) ;
333- assert ! ( !has_conflicts:: <(
334- & mut C1 ,
335- & mut C2 ,
336- EntityRefExcept <( C1 , C2 ) >,
337- ) >( c) ) ;
338- assert ! ( !has_conflicts:: <(
339- & mut C1 ,
340- EntityRefExcept <( C1 , C2 ) >,
341- & mut C2 ,
342- ) >( c) ) ;
343- assert ! ( !has_conflicts:: <(
344- EntityRefExcept <( C1 , C2 ) >,
345- & mut C1 ,
346- & mut C2 ,
347- ) >( c) ) ;
394+ assert ! ( has_conflicts:: <( EntityRefExcept <C1 >, & mut C1 ) >( c) . is_ok( ) ) ;
395+ assert ! ( has_conflicts:: <( & mut C1 , EntityRefExcept <C1 >) >( c) . is_ok( ) ) ;
396+ assert ! ( has_conflicts:: <( & C2 , EntityRefExcept <C1 >) >( c) . is_ok( ) ) ;
397+ assert ! ( has_conflicts:: <( & mut C1 , EntityRefExcept <( C1 , C2 ) >, ) >( c) . is_ok( ) ) ;
398+ assert ! ( has_conflicts:: <( EntityRefExcept <( C1 , C2 ) >, & mut C1 , ) >( c) . is_ok( ) ) ;
399+ assert ! ( has_conflicts:: <( & mut C1 , & mut C2 , EntityRefExcept <( C1 , C2 ) >, ) >( c) . is_ok( ) ) ;
400+ assert ! ( has_conflicts:: <( & mut C1 , EntityRefExcept <( C1 , C2 ) >, & mut C2 , ) >( c) . is_ok( ) ) ;
401+ assert ! ( has_conflicts:: <( EntityRefExcept <( C1 , C2 ) >, & mut C1 , & mut C2 , ) >( c) . is_ok( ) ) ;
348402
349403 // Conflicts
350- assert ! ( has_conflicts:: <( EntityRefExcept <C1 >, & mut C2 ) >( c) ) ;
351- assert ! ( has_conflicts:: <( & mut C2 , EntityRefExcept <C1 >) >( c) ) ;
404+ assert ! ( matches!(
405+ has_conflicts:: <( EntityRefExcept <C1 >, & mut C2 ) >( c) ,
406+ Err ( AccessError :: Conflict ( _, _) )
407+ ) ) ;
408+ assert ! ( matches!(
409+ has_conflicts:: <( & mut C2 , EntityRefExcept <C1 >) >( c) ,
410+ Err ( AccessError :: Conflict ( _, _) )
411+ ) ) ;
352412 }
353413
354414 #[ test]
@@ -359,30 +419,30 @@ mod tests {
359419 let c = world. components ( ) ;
360420
361421 // Compatible
362- assert ! ( !has_conflicts:: <( EntityMutExcept <C1 >, & mut C1 ) >( c) ) ;
363- assert ! ( !has_conflicts:: <( & mut C1 , EntityMutExcept <C1 >) >( c) ) ;
364- assert ! ( !has_conflicts:: <( & mut C1 , EntityMutExcept <( C1 , C2 ) >, ) >( c) ) ;
365- assert ! ( !has_conflicts:: <( EntityMutExcept <( C1 , C2 ) >, & mut C1 , ) >( c) ) ;
366- assert ! ( !has_conflicts:: <(
367- & mut C1 ,
368- & mut C2 ,
369- EntityMutExcept <( C1 , C2 ) >,
370- ) >( c) ) ;
371- assert ! ( !has_conflicts:: <(
372- & mut C1 ,
373- EntityMutExcept <( C1 , C2 ) >,
374- & mut C2 ,
375- ) >( c) ) ;
376- assert ! ( !has_conflicts:: <(
377- EntityMutExcept <( C1 , C2 ) >,
378- & mut C1 ,
379- & mut C2 ,
380- ) >( c) ) ;
422+ assert ! ( has_conflicts:: <( EntityMutExcept <C1 >, & mut C1 ) >( c) . is_ok( ) ) ;
423+ assert ! ( has_conflicts:: <( & mut C1 , EntityMutExcept <C1 >) >( c) . is_ok( ) ) ;
424+ assert ! ( has_conflicts:: <( & mut C1 , EntityMutExcept <( C1 , C2 ) >, ) >( c) . is_ok( ) ) ;
425+ assert ! ( has_conflicts:: <( EntityMutExcept <( C1 , C2 ) >, & mut C1 , ) >( c) . is_ok( ) ) ;
426+ assert ! ( has_conflicts:: <( & mut C1 , & mut C2 , EntityMutExcept <( C1 , C2 ) >, ) >( c) . is_ok( ) ) ;
427+ assert ! ( has_conflicts:: <( & mut C1 , EntityMutExcept <( C1 , C2 ) >, & mut C2 , ) >( c) . is_ok( ) ) ;
428+ assert ! ( has_conflicts:: <( EntityMutExcept <( C1 , C2 ) >, & mut C1 , & mut C2 , ) >( c) . is_ok( ) ) ;
381429
382430 // Conflicts
383- assert ! ( has_conflicts:: <( & C2 , EntityMutExcept <C1 >) >( c) ) ;
384- assert ! ( has_conflicts:: <( EntityMutExcept <C1 >, & C2 ) >( c) ) ;
385- assert ! ( has_conflicts:: <( EntityMutExcept <C1 >, & mut C2 ) >( c) ) ;
386- assert ! ( has_conflicts:: <( & mut C2 , EntityMutExcept <C1 >) >( c) ) ;
431+ assert ! ( matches!(
432+ has_conflicts:: <( & C2 , EntityMutExcept <C1 >) >( c) ,
433+ Err ( AccessError :: Conflict ( _, _) )
434+ ) ) ;
435+ assert ! ( matches!(
436+ has_conflicts:: <( EntityMutExcept <C1 >, & C2 ) >( c) ,
437+ Err ( AccessError :: Conflict ( _, _) )
438+ ) ) ;
439+ assert ! ( matches!(
440+ has_conflicts:: <( EntityMutExcept <C1 >, & mut C2 ) >( c) ,
441+ Err ( AccessError :: Conflict ( _, _) )
442+ ) ) ;
443+ assert ! ( matches!(
444+ has_conflicts:: <( & mut C2 , EntityMutExcept <C1 >) >( c) ,
445+ Err ( AccessError :: Conflict ( _, _) )
446+ ) ) ;
387447 }
388448}
0 commit comments