@@ -32,14 +32,17 @@ use crate::{archetype::ArchetypeId, storage::SparseSetIndex};
32
32
use std:: { convert:: TryFrom , fmt, mem, sync:: atomic:: Ordering } ;
33
33
34
34
#[ cfg( target_has_atomic = "64" ) ]
35
- use std:: sync:: atomic:: AtomicI64 as AtomicInt ;
35
+ use std:: sync:: atomic:: AtomicI64 as AtomicIdCursor ;
36
36
#[ cfg( target_has_atomic = "64" ) ]
37
- type Int = i64 ;
37
+ type IdCursor = i64 ;
38
38
39
+ /// Most modern platforms support 64-bit atomics, but some less-common platforms
40
+ /// do not. This fallback allows compilation using a 32-bit cursor instead, with
41
+ /// the caveat that some conversions may fail (and panic) at runtime.
39
42
#[ cfg( not( target_has_atomic = "64" ) ) ]
40
- use std:: sync:: atomic:: AtomicI32 as AtomicInt ;
43
+ use std:: sync:: atomic:: AtomicIsize as AtomicIdCursor ;
41
44
#[ cfg( not( target_has_atomic = "64" ) ) ]
42
- type Int = i32 ;
45
+ type IdCursor = isize ;
43
46
44
47
/// Lightweight unique ID of an entity.
45
48
///
@@ -243,7 +246,7 @@ pub struct Entities {
243
246
///
244
247
/// Once `flush()` is done, `free_cursor` will equal `pending.len()`.
245
248
pending : Vec < u32 > ,
246
- free_cursor : AtomicInt ,
249
+ free_cursor : AtomicIdCursor ,
247
250
/// Stores the number of free entities for [`len`](Entities::len)
248
251
len : u32 ,
249
252
}
@@ -256,8 +259,12 @@ impl Entities {
256
259
// Use one atomic subtract to grab a range of new IDs. The range might be
257
260
// entirely nonnegative, meaning all IDs come from the freelist, or entirely
258
261
// negative, meaning they are all new IDs to allocate, or a mix of both.
259
- let range_end = self . free_cursor . fetch_sub ( count as Int , Ordering :: Relaxed ) ;
260
- let range_start = range_end - count as Int ;
262
+ let range_end = self
263
+ . free_cursor
264
+ // Unwrap: these conversions can only fail on platforms that don't support 64-bit atomics
265
+ // and use AtomicIsize instead (see note on `IdCursor`).
266
+ . fetch_sub ( IdCursor :: try_from ( count) . unwrap ( ) , Ordering :: Relaxed ) ;
267
+ let range_start = range_end - IdCursor :: try_from ( count) . unwrap ( ) ;
261
268
262
269
let freelist_range = range_start. max ( 0 ) as usize ..range_end. max ( 0 ) as usize ;
263
270
@@ -274,7 +281,7 @@ impl Entities {
274
281
// In this example, we truncate the end to 0, leaving us with `-3..0`.
275
282
// Then we negate these values to indicate how far beyond the end of `meta.end()`
276
283
// to go, yielding `meta.len()+0 .. meta.len()+3`.
277
- let base = self . meta . len ( ) as Int ;
284
+ let base = self . meta . len ( ) as IdCursor ;
278
285
279
286
let new_id_end = u32:: try_from ( base - range_start) . expect ( "too many entities" ) ;
280
287
@@ -311,7 +318,7 @@ impl Entities {
311
318
// and farther beyond `meta.len()`.
312
319
Entity {
313
320
generation : 0 ,
314
- id : u32:: try_from ( self . meta . len ( ) as Int - n) . expect ( "too many entities" ) ,
321
+ id : u32:: try_from ( self . meta . len ( ) as IdCursor - n) . expect ( "too many entities" ) ,
315
322
}
316
323
}
317
324
}
@@ -329,7 +336,7 @@ impl Entities {
329
336
self . verify_flushed ( ) ;
330
337
self . len += 1 ;
331
338
if let Some ( id) = self . pending . pop ( ) {
332
- let new_free_cursor = self . pending . len ( ) as Int ;
339
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
333
340
* self . free_cursor . get_mut ( ) = new_free_cursor;
334
341
Entity {
335
342
generation : self . meta [ id as usize ] . generation ,
@@ -351,14 +358,14 @@ impl Entities {
351
358
352
359
let loc = if entity. id as usize >= self . meta . len ( ) {
353
360
self . pending . extend ( ( self . meta . len ( ) as u32 ) ..entity. id ) ;
354
- let new_free_cursor = self . pending . len ( ) as Int ;
361
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
355
362
* self . free_cursor . get_mut ( ) = new_free_cursor;
356
363
self . meta . resize ( entity. id as usize + 1 , EntityMeta :: EMPTY ) ;
357
364
self . len += 1 ;
358
365
None
359
366
} else if let Some ( index) = self . pending . iter ( ) . position ( |item| * item == entity. id ) {
360
367
self . pending . swap_remove ( index) ;
361
- let new_free_cursor = self . pending . len ( ) as Int ;
368
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
362
369
* self . free_cursor . get_mut ( ) = new_free_cursor;
363
370
self . len += 1 ;
364
371
None
@@ -382,14 +389,14 @@ impl Entities {
382
389
383
390
let result = if entity. id as usize >= self . meta . len ( ) {
384
391
self . pending . extend ( ( self . meta . len ( ) as u32 ) ..entity. id ) ;
385
- let new_free_cursor = self . pending . len ( ) as Int ;
392
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
386
393
* self . free_cursor . get_mut ( ) = new_free_cursor;
387
394
self . meta . resize ( entity. id as usize + 1 , EntityMeta :: EMPTY ) ;
388
395
self . len += 1 ;
389
396
AllocAtWithoutReplacement :: DidNotExist
390
397
} else if let Some ( index) = self . pending . iter ( ) . position ( |item| * item == entity. id ) {
391
398
self . pending . swap_remove ( index) ;
392
- let new_free_cursor = self . pending . len ( ) as Int ;
399
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
393
400
* self . free_cursor . get_mut ( ) = new_free_cursor;
394
401
self . len += 1 ;
395
402
AllocAtWithoutReplacement :: DidNotExist
@@ -424,7 +431,7 @@ impl Entities {
424
431
425
432
self . pending . push ( entity. id ) ;
426
433
427
- let new_free_cursor = self . pending . len ( ) as Int ;
434
+ let new_free_cursor = self . pending . len ( ) as IdCursor ;
428
435
* self . free_cursor . get_mut ( ) = new_free_cursor;
429
436
self . len -= 1 ;
430
437
Some ( loc)
@@ -435,7 +442,9 @@ impl Entities {
435
442
self . verify_flushed ( ) ;
436
443
437
444
let freelist_size = * self . free_cursor . get_mut ( ) ;
438
- let shortfall = additional as Int - freelist_size;
445
+ // Unwrap: these conversions can only fail on platforms that don't support 64-bit atomics
446
+ // and use AtomicIsize instead (see note on `IdCursor`).
447
+ let shortfall = IdCursor :: try_from ( additional) . unwrap ( ) - freelist_size;
439
448
if shortfall > 0 {
440
449
self . meta . reserve ( shortfall as usize ) ;
441
450
}
@@ -492,7 +501,7 @@ impl Entities {
492
501
}
493
502
494
503
fn needs_flush ( & mut self ) -> bool {
495
- * self . free_cursor . get_mut ( ) != self . pending . len ( ) as Int
504
+ * self . free_cursor . get_mut ( ) != self . pending . len ( ) as IdCursor
496
505
}
497
506
498
507
/// Allocates space for entities previously reserved with `reserve_entity` or
0 commit comments