@@ -40,11 +40,20 @@ pub use self::serde::*;
40
40
pub use map_entities:: * ;
41
41
42
42
use crate :: { archetype:: ArchetypeId , storage:: SparseSetIndex } ;
43
- use std:: {
44
- convert:: TryFrom ,
45
- fmt, mem,
46
- sync:: atomic:: { AtomicI64 , Ordering } ,
47
- } ;
43
+ use std:: { convert:: TryFrom , fmt, mem, sync:: atomic:: Ordering } ;
44
+
45
+ #[ cfg( target_has_atomic = "64" ) ]
46
+ use std:: sync:: atomic:: AtomicI64 as AtomicIdCursor ;
47
+ #[ cfg( target_has_atomic = "64" ) ]
48
+ type IdCursor = i64 ;
49
+
50
+ /// Most modern platforms support 64-bit atomics, but some less-common platforms
51
+ /// do not. This fallback allows compilation using a 32-bit cursor instead, with
52
+ /// the caveat that some conversions may fail (and panic) at runtime.
53
+ #[ cfg( not( target_has_atomic = "64" ) ) ]
54
+ use std:: sync:: atomic:: AtomicIsize as AtomicIdCursor ;
55
+ #[ cfg( not( target_has_atomic = "64" ) ) ]
56
+ type IdCursor = isize ;
48
57
49
58
/// Lightweight identifier of an [entity](crate::entity).
50
59
///
@@ -291,7 +300,7 @@ pub struct Entities {
291
300
///
292
301
/// Once `flush()` is done, `free_cursor` will equal `pending.len()`.
293
302
pending : Vec < u32 > ,
294
- free_cursor : AtomicI64 ,
303
+ free_cursor : AtomicIdCursor ,
295
304
/// Stores the number of free entities for [`len`](Entities::len)
296
305
len : u32 ,
297
306
}
@@ -304,8 +313,12 @@ impl Entities {
304
313
// Use one atomic subtract to grab a range of new IDs. The range might be
305
314
// entirely nonnegative, meaning all IDs come from the freelist, or entirely
306
315
// negative, meaning they are all new IDs to allocate, or a mix of both.
307
- let range_end = self . free_cursor . fetch_sub ( count as i64 , Ordering :: Relaxed ) ;
308
- let range_start = range_end - count as i64 ;
316
+ let range_end = self
317
+ . free_cursor
318
+ // Unwrap: these conversions can only fail on platforms that don't support 64-bit atomics
319
+ // and use AtomicIsize instead (see note on `IdCursor`).
320
+ . fetch_sub ( IdCursor :: try_from ( count) . unwrap ( ) , Ordering :: Relaxed ) ;
321
+ let range_start = range_end - IdCursor :: try_from ( count) . unwrap ( ) ;
309
322
310
323
let freelist_range = range_start. max ( 0 ) as usize ..range_end. max ( 0 ) as usize ;
311
324
@@ -322,7 +335,7 @@ impl Entities {
322
335
// In this example, we truncate the end to 0, leaving us with `-3..0`.
323
336
// Then we negate these values to indicate how far beyond the end of `meta.end()`
324
337
// to go, yielding `meta.len()+0 .. meta.len()+3`.
325
- let base = self . meta . len ( ) as i64 ;
338
+ let base = self . meta . len ( ) as IdCursor ;
326
339
327
340
let new_id_end = u32:: try_from ( base - range_start) . expect ( "too many entities" ) ;
328
341
@@ -359,7 +372,7 @@ impl Entities {
359
372
// and farther beyond `meta.len()`.
360
373
Entity {
361
374
generation : 0 ,
362
- id : u32:: try_from ( self . meta . len ( ) as i64 - n) . expect ( "too many entities" ) ,
375
+ id : u32:: try_from ( self . meta . len ( ) as IdCursor - n) . expect ( "too many entities" ) ,
363
376
}
364
377
}
365
378
}
@@ -377,7 +390,7 @@ impl Entities {
377
390
self . verify_flushed ( ) ;
378
391
self . len += 1 ;
379
392
if let Some ( id) = self . pending . pop ( ) {
380
- let new_free_cursor = self . pending . len ( ) as i64 ;
393
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
381
394
* self . free_cursor . get_mut ( ) = new_free_cursor;
382
395
Entity {
383
396
generation : self . meta [ id as usize ] . generation ,
@@ -399,14 +412,14 @@ impl Entities {
399
412
400
413
let loc = if entity. id as usize >= self . meta . len ( ) {
401
414
self . pending . extend ( ( self . meta . len ( ) as u32 ) ..entity. id ) ;
402
- let new_free_cursor = self . pending . len ( ) as i64 ;
415
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
403
416
* self . free_cursor . get_mut ( ) = new_free_cursor;
404
417
self . meta . resize ( entity. id as usize + 1 , EntityMeta :: EMPTY ) ;
405
418
self . len += 1 ;
406
419
None
407
420
} else if let Some ( index) = self . pending . iter ( ) . position ( |item| * item == entity. id ) {
408
421
self . pending . swap_remove ( index) ;
409
- let new_free_cursor = self . pending . len ( ) as i64 ;
422
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
410
423
* self . free_cursor . get_mut ( ) = new_free_cursor;
411
424
self . len += 1 ;
412
425
None
@@ -430,14 +443,14 @@ impl Entities {
430
443
431
444
let result = if entity. id as usize >= self . meta . len ( ) {
432
445
self . pending . extend ( ( self . meta . len ( ) as u32 ) ..entity. id ) ;
433
- let new_free_cursor = self . pending . len ( ) as i64 ;
446
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
434
447
* self . free_cursor . get_mut ( ) = new_free_cursor;
435
448
self . meta . resize ( entity. id as usize + 1 , EntityMeta :: EMPTY ) ;
436
449
self . len += 1 ;
437
450
AllocAtWithoutReplacement :: DidNotExist
438
451
} else if let Some ( index) = self . pending . iter ( ) . position ( |item| * item == entity. id ) {
439
452
self . pending . swap_remove ( index) ;
440
- let new_free_cursor = self . pending . len ( ) as i64 ;
453
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
441
454
* self . free_cursor . get_mut ( ) = new_free_cursor;
442
455
self . len += 1 ;
443
456
AllocAtWithoutReplacement :: DidNotExist
@@ -472,7 +485,7 @@ impl Entities {
472
485
473
486
self . pending . push ( entity. id ) ;
474
487
475
- let new_free_cursor = self . pending . len ( ) as i64 ;
488
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
476
489
* self . free_cursor . get_mut ( ) = new_free_cursor;
477
490
self . len -= 1 ;
478
491
Some ( loc)
@@ -483,7 +496,9 @@ impl Entities {
483
496
self . verify_flushed ( ) ;
484
497
485
498
let freelist_size = * self . free_cursor . get_mut ( ) ;
486
- let shortfall = additional as i64 - freelist_size;
499
+ // Unwrap: these conversions can only fail on platforms that don't support 64-bit atomics
500
+ // and use AtomicIsize instead (see note on `IdCursor`).
501
+ let shortfall = IdCursor :: try_from ( additional) . unwrap ( ) - freelist_size;
487
502
if shortfall > 0 {
488
503
self . meta . reserve ( shortfall as usize ) ;
489
504
}
@@ -540,7 +555,7 @@ impl Entities {
540
555
}
541
556
542
557
fn needs_flush ( & mut self ) -> bool {
543
- * self . free_cursor . get_mut ( ) != self . pending . len ( ) as i64
558
+ * self . free_cursor . get_mut ( ) != self . pending . len ( ) as IdCursor
544
559
}
545
560
546
561
/// Allocates space for entities previously reserved with `reserve_entity` or
0 commit comments