Skip to main content

bevy_ecs/entity/
remote_allocator.rs

1//! This module contains the guts of Bevy's entity allocator.
2//!
3//! Entity allocation needs to work concurrently and remotely.
4//! Remote allocations (where no reference to the world is held) is needed for long running tasks, such as loading assets on separate threads.
5//! Non-remote, "normal" allocation needs to be as fast as possible while still supporting remote allocation.
6//!
7//! The allocator fundamentally is made of a cursor for the next fresh, never used [`EntityIndex`] and a free list.
8//! The free list is a collection that holds [`Entity`] values that were used and can be reused; they are "free"/available.
9//! If the free list is empty, it's really simple to just increment the fresh index cursor.
10//! The tricky part is implementing a remotely accessible free list.
11//!
12//! A naive free list could just a concurrent queue.
13//! That would probably be fine for remote allocation but for non-remote, we can go much faster.
14//! In particular, a concurrent queue must do additional work to handle cases where something is added concurrently with being removed.
15//! But for non-remote allocation, we can guarantee that no free will happen during an allocation since `free` needs mutably access to the world already.
16//! That means, we can skip a lot of those safety checks.
17//! Plus, we know the maximum size of the free list ahead of time, since we can assume there are no duplicates.
18//! That means, we can have a much more efficient allocation scheme, far better than a linked list.
19//!
20//! For the free list, the list needs to be pinned in memory and yet grow-able.
21//! That's quite the pickle, but by splitting the growth over multiple arrays, this isn't so bad.
22//! When the list needs to grow, we just *add* on another array to the buffer (instead of *replacing* the old one with a bigger one).
23//! These arrays are called [`Chunk`]s.
24//! This keeps everything pinned, and since we know the maximum size ahead of time, we can make this mapping very fast.
25//!
26//! Similar to how `Vec` is implemented, the free list is implemented as a [`FreeBuffer`] (handling allocations and implicit capacity)
27//! and the [`FreeCount`] manages the length of the free list.
28//! The free list's item is a [`Slot`], which manages accessing each item concurrently.
29//!
30//! These types are summed up in [`SharedAllocator`], which is highly unsafe.
31//! The interfaces [`Allocator`] and [`RemoteAllocator`] provide safe interfaces to them.
32
33use arrayvec::ArrayVec;
34use bevy_platform::{
35    prelude::{Box, Vec},
36    sync::{
37        atomic::{AtomicBool, AtomicPtr, AtomicU32, AtomicU64, Ordering},
38        Arc,
39    },
40};
41use core::mem::ManuallyDrop;
42use log::warn;
43use nonmax::NonMaxU32;
44
45use crate::query::DebugCheckedUnwrap;
46
47use super::{Entity, EntityIndex, EntitySetIterator};
48
49/// This is the item we store in the free list.
50/// Effectively, this is a `MaybeUninit<Entity>` where uninit is represented by `Entity::PLACEHOLDER`.
51///
52/// This uses atomics to allow optimistic reads.
53/// It is UB for a non-atomic read to race with a non-atomic write,
54/// even if the value that is read is never used.
55/// `remote_alloc()` performs an unsynchronized read on a `Slot`,
56/// and then attempts to claim the value using a `compare_exchange`.
57/// Another thread could write that same `Slot` if it performs a
58/// `remote_alloc()` followed by a `free()`,
59/// so the read and write must be atomic.
60#[repr(C, align(8))]
61struct Slot {
62    #[cfg(not(target_has_atomic = "64"))]
63    #[cfg(target_endian = "little")]
64    low_bits: AtomicU32,
65    #[cfg(not(target_has_atomic = "64"))]
66    high_bits: AtomicU32,
67    #[cfg(not(target_has_atomic = "64"))]
68    #[cfg(target_endian = "big")]
69    low_bits: AtomicU32,
70    #[cfg(target_has_atomic = "64")]
71    inner_entity: AtomicU64,
72}
73
74impl Slot {
75    /// Produces a meaningless empty value. This is a valid but incorrect `Entity`.
76    /// It's valid because the bits do represent a valid bit pattern of an `Entity`.
77    /// It's incorrect because this is in the free buffer even though the entity was never freed.
78    /// Importantly, [`FreeCount`] determines which part of the free buffer is the free list.
79    /// An empty slot may be in the free buffer, but should not be in the free list.
80    /// This can be thought of as the `MaybeUninit` uninit in `Vec`'s excess capacity.
81    const fn empty() -> Self {
82        let source = Entity::PLACEHOLDER;
83        #[cfg(not(target_has_atomic = "64"))]
84        return Self {
85            low_bits: AtomicU32::new(source.to_bits() as u32),
86            high_bits: AtomicU32::new((source.to_bits() >> 32) as u32),
87        };
88        #[cfg(target_has_atomic = "64")]
89        return Self {
90            inner_entity: AtomicU64::new(source.to_bits()),
91        };
92    }
93
94    /// Sets the entity at this slot.
95    #[inline]
96    fn set_entity(&self, entity: Entity) {
97        #[cfg(not(target_has_atomic = "64"))]
98        self.low_bits
99            .store(entity.to_bits() as u32, Ordering::Relaxed);
100        #[cfg(not(target_has_atomic = "64"))]
101        self.high_bits
102            .store((entity.to_bits() >> 32) as u32, Ordering::Relaxed);
103        #[cfg(target_has_atomic = "64")]
104        self.inner_entity.store(entity.to_bits(), Ordering::Relaxed);
105    }
106
107    /// Gets the stored entity. The result will be [`Entity::PLACEHOLDER`] unless [`set_entity`](Self::set_entity) has been called.
108    #[inline]
109    fn get_entity(&self) -> Entity {
110        #[cfg(not(target_has_atomic = "64"))]
111        let inner = {
112            (self.low_bits.load(Ordering::Relaxed) as u64)
113                | ((self.high_bits.load(Ordering::Relaxed) as u64) << 32)
114        };
115        #[cfg(target_has_atomic = "64")]
116        let inner = { self.inner_entity.load(Ordering::Relaxed) };
117        // SAFETY: This is always sourced from a proper entity.
118        // Even if the low and high bits don't come from the same entity,
119        // this still forms a valid entity since both the index and generation are valid.
120        unsafe { Entity::try_from_bits(inner).unwrap_unchecked() }
121    }
122}
123
124/// Each chunk stores a buffer of [`Slot`]s at a fixed capacity.
125struct Chunk {
126    /// Points to the first slot. If this is null, we need to allocate it.
127    first: AtomicPtr<Slot>,
128}
129
130impl Chunk {
131    /// Constructs a null [`Chunk`].
132    const fn new() -> Self {
133        Self {
134            first: AtomicPtr::new(core::ptr::null_mut()),
135        }
136    }
137
138    /// Gets the entity at the index within this chunk.
139    ///
140    /// # Safety
141    ///
142    /// [`Self::set`] must have been called on this index before, ensuring it is in bounds and the chunk is initialized.
143    /// If this is not `ATOMIC`, this must have a clear, strict order between this call and the previous `set`s of this `index`.
144    /// Otherwise, the compiler will make unsound optimizations.
145    #[inline]
146    unsafe fn get<const ATOMIC: bool>(&self, index: u32) -> Entity {
147        // Relaxed is fine since caller has already assured memory ordering is satisfied since *some* set.
148        let head = self.first.load(Ordering::Relaxed);
149        // SAFETY: caller ensures we are in bounds and init (because `set` must be in bounds)
150        let target = unsafe { &*head.add(index as usize) };
151        if ATOMIC {
152            target.get_entity()
153        } else {
154            // SAFETY: Caller ensures memory ordering.
155            // The `Slot` has the same memory representation as `u64`
156            // and currently represents a valid entity value because this is not concurrent with any `free`.
157            unsafe {
158                let bits = core::ptr::from_ref(target).cast::<u64>().read();
159                Entity::try_from_bits(bits).unwrap_unchecked()
160            }
161        }
162    }
163
164    /// Gets a slice of indices.
165    ///
166    /// # Safety
167    ///
168    /// [`Self::set`] must have been called on these indices before, ensuring it is in bounds and the chunk is initialized.
169    #[inline]
170    unsafe fn get_slice(&self, index: u32, ideal_len: u32, chunk_capacity: u32) -> &[Slot] {
171        let after_index_slice_len = chunk_capacity - index;
172        let len = after_index_slice_len.min(ideal_len) as usize;
173
174        // Relaxed is fine since caller ensures we are initialized already.
175        // In order for the caller to guarantee that, they must have an ordering that orders this `get` after the required `set`.
176        let head = self.first.load(Ordering::Relaxed);
177
178        // SAFETY: Caller ensures we are init, so the chunk was allocated via a `Vec` and the index is within the capacity.
179        unsafe { core::slice::from_raw_parts(head.add(index as usize), len) }
180    }
181
182    /// Sets this entity at this index.
183    ///
184    /// # Safety
185    ///
186    /// Index must be in bounds.
187    /// This must not be called on the same chunk concurrently.
188    /// There must be a clear, strict order between this call and the previous `set`s of this `index`.
189    #[inline]
190    unsafe fn set(&self, index: u32, entity: Entity, chunk_capacity: u32) {
191        // Relaxed is fine here since the caller ensures memory ordering.
192        let ptr = self.first.load(Ordering::Relaxed);
193        let head = if ptr.is_null() {
194            // SAFETY: Ensured by caller.
195            unsafe { self.init(chunk_capacity) }
196        } else {
197            ptr
198        };
199
200        // SAFETY: caller ensures it is in bounds and we are not fighting with other `set` calls or `get` calls.
201        // A race condition is therefore impossible.
202        // The address can't wrap or pass isize max since this addition is within an allocation.
203        // For that to happen, you would first run out of memory in practice.
204        let target = unsafe { &*head.add(index as usize) };
205
206        target.set_entity(entity);
207    }
208
209    /// Initializes the chunk to be valid, returning the pointer.
210    ///
211    /// # Safety
212    ///
213    /// This must not be called concurrently with itself.
214    #[cold]
215    unsafe fn init(&self, chunk_capacity: u32) -> *mut Slot {
216        let mut buff = ManuallyDrop::new(Vec::new());
217        buff.reserve_exact(chunk_capacity as usize);
218        buff.resize_with(chunk_capacity as usize, Slot::empty);
219        let ptr = buff.as_mut_ptr();
220        // Relaxed is fine here since this is not called concurrently.
221        self.first.store(ptr, Ordering::Relaxed);
222        ptr
223    }
224
225    /// Frees memory
226    ///
227    /// # Safety
228    ///
229    /// `chunk_capacity` must be the same as it was initialized with.
230    unsafe fn dealloc(&mut self, chunk_capacity: u32) {
231        let to_drop = *self.first.get_mut();
232        if !to_drop.is_null() {
233            // SAFETY: This was created in [`Self::init`] from a standard Vec.
234            unsafe {
235                Vec::from_raw_parts(to_drop, chunk_capacity as usize, chunk_capacity as usize);
236            }
237        }
238    }
239}
240
241/// This is a buffer that has been split into power-of-two sized chunks, so that each chunk is pinned in memory.
242/// Conceptually, each chunk is put end-to-end to form the buffer. This ultimately avoids copying elements on resize,
243/// while allowing it to expand in capacity as needed. A separate system must track the length of the list in the buffer.
244/// Each chunk is twice as large as the last, except for the first two which have a capacity of 512.
245struct FreeBuffer([Chunk; Self::NUM_CHUNKS as usize]);
246
247impl FreeBuffer {
248    const NUM_CHUNKS: u32 = 24;
249    const NUM_SKIPPED: u32 = u32::BITS - Self::NUM_CHUNKS;
250
251    /// Constructs an empty [`FreeBuffer`].
252    const fn new() -> Self {
253        Self([const { Chunk::new() }; Self::NUM_CHUNKS as usize])
254    }
255
256    /// Computes the capacity of the chunk at this index within [`Self::NUM_CHUNKS`].
257    /// The first 2 have length 512 (2^9) and the last has length (2^31)
258    #[inline]
259    const fn capacity_of_chunk(chunk_index: u32) -> u32 {
260        // We do this because we're skipping the first `NUM_SKIPPED` powers, so we need to make up for them by doubling the first index.
261        // This is why the first 2 indices both have a capacity of 512.
262        let corrected = if chunk_index == 0 { 1 } else { chunk_index };
263        // We add NUM_SKIPPED because the total capacity should be as if [`Self::NUM_CHUNKS`] were 32.
264        // This skips the first NUM_SKIPPED powers.
265        let corrected = corrected + Self::NUM_SKIPPED;
266        // This bit shift is just 2^corrected.
267        1 << corrected
268    }
269
270    /// For this index in the whole buffer, returns the index of the [`Chunk`], the index within that chunk, and the capacity of that chunk.
271    #[inline]
272    const fn index_info(full_index: u32) -> (u32, u32, u32) {
273        // We do a `saturating_sub` because we skip the first `NUM_SKIPPED` powers to make space for the first chunk's entity count.
274        // The -1 is because this is the number of chunks, but we want the index in the end.
275        // We store chunks in smallest to biggest order, so we need to reverse it.
276        let chunk_index = (Self::NUM_CHUNKS - 1).saturating_sub(full_index.leading_zeros());
277        let chunk_capacity = Self::capacity_of_chunk(chunk_index);
278        // We only need to cut off this particular bit.
279        // The capacity is only one bit, and if other bits needed to be dropped, `leading` would have been greater
280        let index_in_chunk = full_index & !chunk_capacity;
281
282        (chunk_index, index_in_chunk, chunk_capacity)
283    }
284
285    /// For this index in the whole buffer, returns the [`Chunk`], the index within that chunk, and the capacity of that chunk.
286    #[inline]
287    fn index_in_chunk(&self, full_index: u32) -> (&Chunk, u32, u32) {
288        let (chunk_index, index_in_chunk, chunk_capacity) = Self::index_info(full_index);
289        // SAFETY: The `index_info` is correct.
290        let chunk = unsafe { self.0.get_unchecked(chunk_index as usize) };
291        (chunk, index_in_chunk, chunk_capacity)
292    }
293
294    /// Gets the entity at an index.
295    ///
296    /// # Safety
297    ///
298    /// [`set`](Self::set) must have been called on this index to initialize its memory.
299    /// If this is not `ATOMIC`, this must have a clear, strict order between this call and the previous `set`s of this `index`.
300    /// Otherwise, the compiler will make unsound optimizations.
301    unsafe fn get<const ATOMIC: bool>(&self, full_index: u32) -> Entity {
302        let (chunk, index, _) = self.index_in_chunk(full_index);
303        // SAFETY: Ensured by caller.
304        unsafe { chunk.get::<ATOMIC>(index) }
305    }
306
307    /// Sets an entity at an index.
308    ///
309    /// # Safety
310    ///
311    /// This must not be called on the same buffer concurrently.
312    /// There must be a clear, strict order between this call and the previous `set`s of this `index`.
313    /// Otherwise, the compiler will make unsound optimizations.
314    #[inline]
315    unsafe fn set(&self, full_index: u32, entity: Entity) {
316        let (chunk, index, chunk_capacity) = self.index_in_chunk(full_index);
317        // SAFETY: Ensured by caller and that the index is correct.
318        unsafe { chunk.set(index, entity, chunk_capacity) }
319    }
320
321    /// Iterates the entities in these indices.
322    ///
323    /// # Safety
324    ///
325    /// [`Self::set`] must have been called on these indices before to initialize memory.
326    /// There must be a clear, strict order between this call and the previous uses of these `indices`.
327    /// Note that until the returned value is dropped, these `indices` are still being accessed,
328    /// making safety for other operations afterward need careful justification.
329    /// Otherwise, the compiler will make unsound optimizations.
330    #[inline]
331    unsafe fn iter(&self, indices: core::ops::Range<u32>) -> FreeBufferIterator<'_> {
332        FreeBufferIterator {
333            buffer: self,
334            future_buffer_indices: indices,
335            current_chunk_slice: [].iter(),
336        }
337    }
338}
339
340impl Drop for FreeBuffer {
341    fn drop(&mut self) {
342        for index in 0..Self::NUM_CHUNKS {
343            let capacity = Self::capacity_of_chunk(index);
344            // SAFETY: we have `&mut` and the capacity is correct.
345            unsafe { self.0[index as usize].dealloc(capacity) };
346        }
347    }
348}
349
350/// An iterator over a [`FreeBuffer`].
351///
352/// # Safety
353///
354/// [`FreeBuffer::set`] must have been called on these indices beforehand to initialize memory.
355struct FreeBufferIterator<'a> {
356    buffer: &'a FreeBuffer,
357    /// The part of the buffer we are iterating at the moment.
358    current_chunk_slice: core::slice::Iter<'a, Slot>,
359    /// The indices in the buffer that are not yet in `current_chunk_slice`.
360    future_buffer_indices: core::ops::Range<u32>,
361}
362
363impl<'a> Iterator for FreeBufferIterator<'a> {
364    type Item = Entity;
365
366    #[inline]
367    fn next(&mut self) -> Option<Self::Item> {
368        if let Some(found) = self.current_chunk_slice.next() {
369            return Some(found.get_entity());
370        }
371
372        let still_need = self.future_buffer_indices.len() as u32;
373        if still_need == 0 {
374            return None;
375        }
376        let next_index = self.future_buffer_indices.start;
377        let (chunk, index, chunk_capacity) = self.buffer.index_in_chunk(next_index);
378
379        // SAFETY: Assured by `FreeBuffer::iter`
380        let slice = unsafe { chunk.get_slice(index, still_need, chunk_capacity) };
381        self.future_buffer_indices.start += slice.len() as u32;
382        self.current_chunk_slice = slice.iter();
383
384        // SAFETY: Constructor ensures these indices are valid in the buffer; the buffer is not sparse, and we just got the next slice.
385        // So the only way for the slice to be empty is if the constructor did not uphold safety.
386        let next = unsafe { self.current_chunk_slice.next().debug_checked_unwrap() };
387        Some(next.get_entity())
388    }
389
390    #[inline]
391    fn size_hint(&self) -> (usize, Option<usize>) {
392        let len = self.future_buffer_indices.len() + self.current_chunk_slice.len();
393        (len, Some(len))
394    }
395}
396
397impl<'a> ExactSizeIterator for FreeBufferIterator<'a> {}
398impl<'a> core::iter::FusedIterator for FreeBufferIterator<'a> {}
399
400/// This tracks the state of a [`FreeCount`], which has lots of information packed into it.
401///
402/// This has three jobs:
403///
404///  - First, obviously, this needs to track the length of the free list.
405///    When the length is 0, we use the [`FreshAllocator`]; otherwise, we pop.
406///    The length also tells us where on the list to push freed entities to.
407///  - Second, we need to be able to "freeze" the length for remote allocations.
408///    This happens when pushing to the list; we need to prevent a push and remote pop from happening at the same time.
409///    We call this "disabling the length".
410///    When it is disabled, only the thing that disabled it is allowed to re-enable it.
411///    This is like a mutex, but it's faster because we pack the mutex into the same bits as the state.
412///    See [`FreeCount::disable_len_for_state`] and [`FreeCount::set_state_risky`] for how this can be done.
413///  - Third, we need to track the generation of the free list.
414///    That is, any two distinct states of the free list, even if they are the same length, must have different [`FreeCount`] values.
415///    This becomes important when a remote allocator needs to know if the information it is working with has been outdated.
416///    See [`FreeList::remote_alloc`] for why this is so important.
417///
418/// As if that isn't hard enough, we need to do all three of these things in the same [`AtomicU64`] for performance.
419/// Not only that, but for memory ordering guarantees, we need to be able to change the length and generation in a single atomic operation.
420/// We do that with a very specific bit layout:
421///
422/// - The least significant 33 bits store a signed 33 bit integer for the length.
423///   This behaves like a u33, but we define `1 << 32` as 0.
424/// - The 34th bit stores a flag that indicates if the length has been disabled.
425/// - The remaining 30 bits are the generation.
426///   The generation helps differentiates different versions of the state that happen to encode the same length.
427///
428/// Why this layout?
429/// A few observations:
430/// First, since the disabling mechanic acts as a mutex, we only need one bit for that, and we can use bit operations to interact with it.
431/// That leaves the length and the generation (which we need to distinguish between two states of the free list that happen to be the same length).
432/// Every change to the length must be/cause a change to the [`FreeCountState`] such that the new state does not equal any previous state.
433/// The second observation is that we only need to change the generation when we move the length in one direction.
434/// Here, we tie popping/allocation to a generation change.
435/// When the length increases, the length part of the state changes, so a generation change is a moot point. (Ex `L0-G0` -> `L1G0`)
436/// When the length decreases, we also need to change the generation to distinguish the states. (Ex `L1-G0` -> `L0G1`)
437///
438/// We need the generation to freely wrap.
439/// In this case, the generation is 30 bits, so after 2 ^ 30 allocations, the generation will wrap.
440/// That is technically a soundness concern,
441/// but it would only cause a problem if the same [`FreeList::remote_alloc`] procedure had been sleeping for all 2 ^ 30 allocations and then when it woke up, all 2 ^ 30 allocations had been freed.
442/// This is impossibly unlikely and is safely ignored in other concurrent queue implementations.
443/// Still, we need the generation to wrap; it must not overflow into the length bits.
444/// As a result, the generation bits *must* be the most significant; this allows them to wrap freely.
445///
446/// It is convenient to put the disabling bit next since that leaves the length bits already aligned to the least significant bits.
447/// That saves us a bit shift!
448///
449/// But now we need to stop the length information from messing with the generation or disabling bits.
450/// Preventing overflow is easy since we can assume the list is unique and there are only `u32::MAX` [`Entity`] values.
451/// We can't prevent underflow with just 32 bits, and performance prevents us from running checks before a subtraction.
452/// But we do know that it can't overflow more than `u32::MAX` times because that would cause the [`FreshAllocator`] to overflow and panic for allocating too many entities.
453/// That means we need to represent "length" values in `±u32::MAX` range, which gives us an `i33` that we then saturatingly cast to `u32`.
454/// As mentioned above, we represent this `i33` as a `u33` where we define `1 << 32` as 0.
455/// This representation works slightly easier for the `saturating_sub` in [`FreeCountState::length`] than a true `i33` representation.
456#[derive(Clone, Copy)]
457struct FreeCountState(u64);
458
459impl FreeCountState {
460    /// When this bit is on, the count is disabled.
461    /// This is used to prevent remote allocations from running at the same time as a free operation.
462    const DISABLING_BIT: u64 = 1 << 33;
463    /// This is the mask for the length bits.
464    const LENGTH_MASK: u64 = (1 << 32) | u32::MAX as u64;
465    /// This is the value of the length mask we consider to be 0.
466    const LENGTH_0: u64 = 1 << 32;
467    /// This is the lowest bit in the u30 generation.
468    const GENERATION_LEAST_BIT: u64 = 1 << 34;
469
470    /// Constructs a length of 0.
471    const fn new_zero_len() -> Self {
472        Self(Self::LENGTH_0)
473    }
474
475    /// Gets the encoded length.
476    #[inline]
477    const fn length(self) -> u32 {
478        let unsigned_length = self.0 & Self::LENGTH_MASK;
479        unsigned_length.saturating_sub(Self::LENGTH_0) as u32
480    }
481
482    /// Returns whether or not the count is disabled.
483    #[inline]
484    const fn is_disabled(self) -> bool {
485        (self.0 & Self::DISABLING_BIT) > 0
486    }
487
488    /// Changes only the length of this count to `length`.
489    #[inline]
490    const fn with_length(self, length: u32) -> Self {
491        // Just turns on the "considered zero" bit since this is non-negative.
492        let length = length as u64 | Self::LENGTH_0;
493        Self(self.0 & !Self::LENGTH_MASK | length)
494    }
495
496    /// For popping `num` off the count, subtract the resulting u64.
497    #[inline]
498    const fn encode_pop(num: u32) -> u64 {
499        let subtract_length = num as u64;
500        // Also subtract one from the generation bit.
501        subtract_length | Self::GENERATION_LEAST_BIT
502    }
503
504    /// Returns the count after popping off `num` elements.
505    #[inline]
506    const fn pop(self, num: u32) -> Self {
507        Self(self.0.wrapping_sub(Self::encode_pop(num)))
508    }
509}
510
511/// This is an atomic interface to [`FreeCountState`].
512struct FreeCount(AtomicU64);
513
514impl FreeCount {
515    /// Constructs a length of 0.
516    const fn new_zero_len() -> Self {
517        Self(AtomicU64::new(FreeCountState::new_zero_len().0))
518    }
519
520    /// Gets the current state of the buffer.
521    #[inline]
522    fn state(&self, order: Ordering) -> FreeCountState {
523        FreeCountState(self.0.load(order))
524    }
525
526    /// Subtracts `num` from the length, returning the previous state.
527    ///
528    /// **NOTE:** Caller should be careful that changing the state is allowed and that the state is not disabled.
529    #[inline]
530    fn pop_for_state(&self, num: u32, order: Ordering) -> FreeCountState {
531        let to_sub = FreeCountState::encode_pop(num);
532        let raw = self.0.fetch_sub(to_sub, order);
533        FreeCountState(raw)
534    }
535
536    /// Marks the state as disabled, returning the previous state
537    /// When the length is disabled, [`try_set_state`](Self::try_set_state) will fail.
538    /// This is used to prevent remote allocation during a free.
539    #[inline]
540    fn disable_len_for_state(&self, order: Ordering) -> FreeCountState {
541        // We don't care about the generation here since this changes the value anyway.
542        FreeCountState(self.0.fetch_or(FreeCountState::DISABLING_BIT, order))
543    }
544
545    /// Sets the state explicitly.
546    /// Caller must be careful that the state has not changed since getting the state and setting it.
547    /// If that happens, the state may not properly reflect the length of the free list or its generation,
548    /// causing entities to be skipped or given out twice.
549    /// This is not a safety concern, but it is a major correctness concern.
550    #[inline]
551    fn set_state_risky(&self, state: FreeCountState, order: Ordering) {
552        self.0.store(state.0, order);
553    }
554
555    /// Attempts to update the state, returning the new [`FreeCountState`] if it fails.
556    #[inline]
557    fn try_set_state(
558        &self,
559        expected_current_state: FreeCountState,
560        target_state: FreeCountState,
561        success: Ordering,
562        failure: Ordering,
563    ) -> Result<(), FreeCountState> {
564        match self
565            .0
566            .compare_exchange(expected_current_state.0, target_state.0, success, failure)
567        {
568            Ok(_) => Ok(()),
569            Err(val) => Err(FreeCountState(val)),
570        }
571    }
572}
573
574/// This is conceptually like a `Vec<Entity>` that stores entities pending reuse.
575struct FreeList {
576    /// The actual buffer of [`Slot`]s.
577    /// Conceptually, this is like the `RawVec` for this `Vec`.
578    buffer: FreeBuffer,
579    /// The length of the free buffer
580    len: FreeCount,
581}
582
583impl FreeList {
584    /// Constructs an empty [`FreeList`].
585    fn new() -> Self {
586        Self {
587            buffer: FreeBuffer::new(),
588            len: FreeCount::new_zero_len(),
589        }
590    }
591
592    /// Gets the number of free entities.
593    ///
594    /// # Risk
595    ///
596    /// For this to be accurate, this must not be called during a [`Self::free`].
597    #[inline]
598    fn num_free(&self) -> u32 {
599        // Relaxed ordering is fine since this doesn't act on the length value in memory.
600        self.len.state(Ordering::Relaxed).length()
601    }
602
603    /// Frees the `entities` allowing them to be reused.
604    ///
605    /// # Safety
606    ///
607    /// There must be a clear, strict order between this call and calls to [`Self::free`], [`Self::alloc_many`], and [`Self::alloc`].
608    /// Otherwise, the compiler will make unsound optimizations.
609    #[inline]
610    unsafe fn free(&self, entities: &[Entity]) {
611        // Disable remote allocation.
612        // `Acquire` ordering pairs with `Release` in `remote_alloc` to ensure every
613        // write to a slot happens after any reads of the old value.
614        let state = self.len.disable_len_for_state(Ordering::Acquire);
615
616        // Append onto the buffer
617        let mut len = state.length();
618        // `for_each` is typically faster than `for` here.
619        entities.iter().for_each(|&entity| {
620            // SAFETY: Caller ensures this does not conflict with `free` or `alloc` calls,
621            // and we just disabled remote allocation with a strict memory ordering.
622            // We only call `set` during a free, and the caller ensures that is not called concurrently.
623            unsafe {
624                self.buffer.set(len, entity);
625            }
626            len += 1;
627        });
628
629        // Update length
630        let new_state = state.with_length(len);
631        // This is safe because `alloc` is not being called and `remote_alloc` checks that it is not disabled.
632        // We don't need to change the generation since this will change the length, which changes the value anyway.
633        // If, from a `remote_alloc` perspective, this does not change the length (i.e. this changes it *back* to what it was),
634        // then `alloc` must have been called, which changes the generation.
635        self.len.set_state_risky(new_state, Ordering::Release);
636    }
637
638    /// Allocates an [`Entity`] from the free list if one is available.
639    ///
640    /// # Safety
641    ///
642    /// There must be a clear, strict order between this call and calls to [`Self::free`].
643    /// Otherwise, the compiler will make unsound optimizations.
644    #[inline]
645    unsafe fn alloc(&self) -> Option<Entity> {
646        // SAFETY: This will get a valid index because caller ensures there is no way for `free` to be done at the same time.
647        // Relaxed is ok here since `free` is the only time memory is changed, and relaxed still gets the most recent state.
648        // The memory ordering to ensure we read the most recent value at the index is ensured by the caller.
649        let len = self.len.pop_for_state(1, Ordering::Relaxed).length();
650        let index = len.checked_sub(1)?;
651
652        // SAFETY: This was less then `len`, so it must have been `set` via `free` before.
653        // This is after `free` because the caller enforces a strict ordering.
654        Some(unsafe { self.buffer.get::<false>(index) })
655    }
656
657    /// Allocates as many [`Entity`]s from the free list as are available, up to `count`.
658    ///
659    /// # Safety
660    ///
661    /// There must be a clear, strict order between this call and calls to [`Self::free`].
662    /// Otherwise, the compiler will make unsound optimizations.
663    ///
664    /// Note that this allocation call doesn't end until the returned value is dropped.
665    /// So, calling [`Self::free`] while the returned value is live is unsound.
666    #[inline]
667    unsafe fn alloc_many(&self, count: u32) -> FreeBufferIterator<'_> {
668        // SAFETY: This will get a valid index because there is no way for `free` to be done at the same time.
669        // Relaxed is ok here since `free` is the only time memory is changed, and relaxed still gets the most recent state.
670        // The memory ordering to ensure we read the most recent value at the index is ensured by the caller.
671        let len = self.len.pop_for_state(count, Ordering::Relaxed).length();
672        let index = len.saturating_sub(count);
673
674        // SAFETY: The iterator's items are all less than the length, so they are in bounds and have been previously set.
675        // There is a strict memory ordering of this use of the indices because the length is only decreasing.
676        // That means there is only one use of these indices since the last call to `free`.
677        // The only time it the length increases is during `free`, which the caller ensures has a "happened before" relationship with this call.
678        unsafe { self.buffer.iter(index..len) }
679    }
680
681    /// Allocates an [`Entity`] from the free list if one is available and it is safe to do so.
682    #[inline]
683    fn remote_alloc(&self) -> Option<Entity> {
684        // The goal is the same as `alloc`, so what's the difference?
685        // `alloc` knows `free` is not being called, but this does not.
686        // What if we `len.fetch_sub(1)` but then `free` overwrites the entity before we could read it?
687        // That would mean we would leak an entity and give another entity out twice.
688        // We get around this by only updating `len` after the read is complete.
689        // But that means something else could be trying to allocate the same index!
690        // So we need a `len.compare_exchange` loop to ensure the index is unique.
691        // Because we keep a generation value in the `FreeCount`, if any of these things happen, we simply try again.
692        // We also need to prevent this from conflicting with a `free` call, so we check to ensure the state is not disabled.
693
694        // We keep track of the attempts so we can yield the thread on std after a few fails.
695        #[cfg(feature = "std")]
696        let mut attempts = 1u32;
697        // We need an acquire ordering to acquire the most recent memory of `free` calls.
698        let mut state = self.len.state(Ordering::Acquire);
699        loop {
700            // The state is only disabled when freeing.
701            // If a free is happening, we need to wait for the new entity to be ready on the free buffer.
702            // That means we will also need to re-fetch the state and acquire the new memory.
703            // Then, we can allocate it.
704            if state.is_disabled() {
705                // Spin 64 times before yielding.
706                #[cfg(feature = "std")]
707                {
708                    attempts += 1;
709                    if attempts.is_multiple_of(64) {
710                        // scheduler probably isn't running the thread doing the `free` call, so yield so it can finish.
711                        std::thread::yield_now();
712                    } else {
713                        core::hint::spin_loop();
714                    }
715                }
716
717                #[cfg(not(feature = "std"))]
718                core::hint::spin_loop();
719
720                // Retry with the fresh state and acquired memory order.
721                state = self.len.state(Ordering::Acquire);
722                continue;
723            }
724
725            // At this point, we know a `free` was not happening when we started.
726
727            let len = state.length();
728            let index = len.checked_sub(1)?;
729
730            // SAFETY: This is within the length, so it must have been initialized.
731            // We used acquire ordering on the state, so this is after any `free`, which would have set the slot.
732            let entity = unsafe { self.buffer.get::<true>(index) };
733
734            let ideal_state = state.pop(1);
735            // If we fail, we need to acquire the new state.
736            // `Release` ordering on success pairs with `Acquire` in `free` to ensure the
737            // read from the slot happens before any future writes.
738            match self
739                .len
740                .try_set_state(state, ideal_state, Ordering::Release, Ordering::Acquire)
741            {
742                Ok(_) => return Some(entity),
743                Err(new_state) => state = new_state,
744            }
745        }
746    }
747}
748
749struct FreshAllocator {
750    /// The next value of [`Entity::index`] to give out if needed.
751    next_entity_index: AtomicU32,
752}
753
754impl FreshAllocator {
755    /// This exists because it may possibly change depending on platform.
756    /// Ex: We may want this to be smaller on 32 bit platforms at some point.
757    const MAX_ENTITIES: u32 = u32::MAX;
758
759    /// The total number of indices given out.
760    #[inline]
761    fn total_entity_indices(&self) -> u32 {
762        self.next_entity_index.load(Ordering::Relaxed)
763    }
764
765    /// This just panics.
766    /// It is included to help with branch prediction, and put the panic message in one spot.
767    #[cold]
768    #[inline]
769    fn on_overflow() -> ! {
770        panic!("too many entities")
771    }
772
773    /// Allocates a fresh [`EntityIndex`].
774    /// This row has never been given out before.
775    #[inline]
776    fn alloc(&self) -> Entity {
777        let index = self.next_entity_index.fetch_add(1, Ordering::Relaxed);
778        if index == Self::MAX_ENTITIES {
779            Self::on_overflow();
780        }
781        // SAFETY: We just checked that this was not max and we only added 1, so we can't have missed it.
782        Entity::from_index(unsafe { EntityIndex::new(NonMaxU32::new_unchecked(index)) })
783    }
784
785    /// Allocates `count` [`EntityIndex`]s.
786    /// These rows will be fresh.
787    /// They have never been given out before.
788    fn alloc_many(&self, count: u32) -> AllocUniqueEntityIndexIterator {
789        let start_new = self.next_entity_index.fetch_add(count, Ordering::Relaxed);
790        let new = match start_new
791            .checked_add(count)
792            .filter(|new| *new < Self::MAX_ENTITIES)
793        {
794            Some(new_next_entity_index) => start_new..new_next_entity_index,
795            None => Self::on_overflow(),
796        };
797        AllocUniqueEntityIndexIterator(new)
798    }
799}
800
801/// An [`Iterator`] returning a sequence of [`EntityIndex`] values from an [`Allocator`] that are never aliased.
802/// These rows have never been given out before.
803///
804/// **NOTE:** Dropping will leak the remaining entity rows!
805pub(super) struct AllocUniqueEntityIndexIterator(core::ops::Range<u32>);
806
807impl Iterator for AllocUniqueEntityIndexIterator {
808    type Item = Entity;
809
810    #[inline]
811    fn next(&mut self) -> Option<Self::Item> {
812        self.0
813            .next()
814            // SAFETY: This came from an *exclusive* range. It can never be max.
815            .map(|idx| unsafe { EntityIndex::new(NonMaxU32::new_unchecked(idx)) })
816            .map(Entity::from_index)
817    }
818
819    #[inline]
820    fn size_hint(&self) -> (usize, Option<usize>) {
821        self.0.size_hint()
822    }
823}
824
825impl ExactSizeIterator for AllocUniqueEntityIndexIterator {}
826impl core::iter::FusedIterator for AllocUniqueEntityIndexIterator {}
827
828/// This stores allocation data shared by all entity allocators.
829struct SharedAllocator {
830    /// The entities pending reuse
831    free: FreeList,
832    fresh: FreshAllocator,
833    /// Tracks whether or not the primary [`Allocator`] has been closed or not.
834    is_closed: AtomicBool,
835}
836
837impl SharedAllocator {
838    /// Constructs a [`SharedAllocator`]
839    fn new() -> Self {
840        Self {
841            free: FreeList::new(),
842            fresh: FreshAllocator {
843                next_entity_index: AtomicU32::new(0),
844            },
845            is_closed: AtomicBool::new(false),
846        }
847    }
848
849    /// Allocates a new [`Entity`], reusing a freed index if one exists.
850    ///
851    /// # Safety
852    ///
853    /// This must not conflict with [`FreeList::free`] calls.
854    #[inline]
855    unsafe fn alloc(&self) -> Entity {
856        // SAFETY: assured by caller
857        unsafe { self.free.alloc() }.unwrap_or_else(|| self.fresh.alloc())
858    }
859
860    /// Allocates a `count` [`Entity`]s, reusing freed indices if they exist.
861    ///
862    /// # Safety
863    ///
864    /// This must not conflict with [`FreeList::free`] calls for the duration of the iterator.
865    #[inline]
866    unsafe fn alloc_many(&self, count: u32) -> AllocEntitiesIterator<'_> {
867        // SAFETY: Ensured by caller.
868        let reused = unsafe { self.free.alloc_many(count) };
869        let still_need = count - reused.len() as u32;
870        let new = self.fresh.alloc_many(still_need);
871        AllocEntitiesIterator { new, reused }
872    }
873
874    /// Allocates a new [`Entity`].
875    /// This will only try to reuse a freed index if it is safe to do so.
876    #[inline]
877    fn remote_alloc(&self) -> Entity {
878        self.free
879            .remote_alloc()
880            .unwrap_or_else(|| self.fresh.alloc())
881    }
882
883    /// Marks the allocator as closed, but it will still function normally.
884    fn close(&self) {
885        self.is_closed.store(true, Ordering::Release);
886    }
887
888    /// Returns true if [`Self::close`] has been called.
889    fn is_closed(&self) -> bool {
890        self.is_closed.load(Ordering::Acquire)
891    }
892}
893
894/// This keeps track of freed entities and allows the allocation of new ones.
895///
896/// Note that this must not implement [`Clone`].
897/// The allocator assumes that it is the only one with [`FreeList::free`] permissions.
898/// If this were cloned, that assumption would be broken, leading to undefined behavior.
899/// This is in contrast to the [`RemoteAllocator`], which may be cloned freely.
900pub(crate) struct Allocator {
901    /// The shared allocator state, which we share with any [`RemoteAllocator`]s.
902    shared: Arc<SharedAllocator>,
903    /// The local free list.
904    /// We use this to amortize the cost of freeing to the shared allocator since that is expensive.
905    local_free: Box<ArrayVec<Entity, 128>>,
906}
907
908impl Default for Allocator {
909    fn default() -> Self {
910        Self::new()
911    }
912}
913
914impl Allocator {
915    /// Constructs a new [`Allocator`]
916    pub(super) fn new() -> Self {
917        Self {
918            shared: Arc::new(SharedAllocator::new()),
919            local_free: Box::new(ArrayVec::new()),
920        }
921    }
922
923    /// Allocates a new [`Entity`], reusing a freed index if one exists.
924    #[inline]
925    pub(super) fn alloc(&self) -> Entity {
926        // SAFETY: violating safety requires a `&mut self` to exist, but rust does not allow that.
927        unsafe { self.shared.alloc() }
928    }
929
930    /// The total number of indices given out.
931    #[inline]
932    pub(crate) fn total_entity_indices(&self) -> u32 {
933        self.shared.fresh.total_entity_indices()
934    }
935
936    /// The number of free entities.
937    #[inline]
938    fn num_free(&self) -> u32 {
939        // RISK: `free` requires mutable access.
940        self.shared.free.num_free()
941    }
942
943    /// Flushes the entities that have been freed locally into the full allocator.
944    /// This is not exposed publicly because it is subject to change.
945    /// It is sometimes useful to call this for tests that depend on the entity allocator behaving more predictably.
946    #[inline]
947    pub(crate) fn flush_freed(&mut self) {
948        // SAFETY: We have `&mut self`.
949        unsafe {
950            self.shared.free.free(self.local_free.as_slice());
951        }
952        self.local_free.clear();
953    }
954
955    /// Frees the entity allowing it to be reused.
956    #[inline]
957    pub(super) fn free(&mut self, entity: Entity) {
958        if self.local_free.is_full() {
959            self.flush_freed();
960        }
961        // SAFETY: The `ArrayVec` is not full or has just been cleared.
962        unsafe {
963            self.local_free.push_unchecked(entity);
964        }
965    }
966
967    /// Allocates `count` entities in an iterator.
968    #[inline]
969    pub(super) fn alloc_many(&self, count: u32) -> AllocEntitiesIterator<'_> {
970        // SAFETY: `free` takes `&mut self`, and this lifetime is captured by the iterator.
971        unsafe { self.shared.alloc_many(count) }
972    }
973
974    /// Frees the entities allowing them to be reused.
975    #[inline]
976    pub(super) fn free_many(&mut self, entities: &[Entity]) {
977        if self.local_free.try_extend_from_slice(entities).is_err() {
978            // SAFETY: We have `&mut self`.
979            unsafe {
980                self.shared.free.free(entities);
981            }
982        }
983    }
984}
985
986impl Drop for Allocator {
987    fn drop(&mut self) {
988        self.shared.close();
989    }
990}
991
992impl core::fmt::Debug for Allocator {
993    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
994        f.debug_struct(core::any::type_name::<Self>())
995            .field("total_indices", &self.total_entity_indices())
996            .field("total_free", &self.num_free())
997            .finish()
998    }
999}
1000
1001/// An [`Iterator`] returning a sequence of [`Entity`] values from an [`Allocator`].
1002///
1003/// **NOTE:** Dropping will leak the remaining entities!
1004pub(super) struct AllocEntitiesIterator<'a> {
1005    new: AllocUniqueEntityIndexIterator,
1006    reused: FreeBufferIterator<'a>,
1007}
1008
1009impl<'a> Iterator for AllocEntitiesIterator<'a> {
1010    type Item = Entity;
1011
1012    fn next(&mut self) -> Option<Self::Item> {
1013        self.reused.next().or_else(|| self.new.next())
1014    }
1015
1016    fn size_hint(&self) -> (usize, Option<usize>) {
1017        let len = self.reused.len() + self.new.len();
1018        (len, Some(len))
1019    }
1020}
1021
1022impl<'a> ExactSizeIterator for AllocEntitiesIterator<'a> {}
1023impl<'a> core::iter::FusedIterator for AllocEntitiesIterator<'a> {}
1024
1025// SAFETY: Newly reserved entity values are unique.
1026unsafe impl EntitySetIterator for AllocEntitiesIterator<'_> {}
1027
1028impl Drop for AllocEntitiesIterator<'_> {
1029    fn drop(&mut self) {
1030        let leaking = self.len();
1031        if leaking > 0 {
1032            warn!(
1033                "{} entities being leaked via unfinished `AllocEntitiesIterator`",
1034                leaking
1035            );
1036        }
1037    }
1038}
1039
1040/// This is a stripped down entity allocator that operates on fewer assumptions than [`EntityAllocator`](super::EntityAllocator).
1041/// As a result, using this will be slower than the main allocator but this offers additional freedoms.
1042/// In particular, this type is fully owned, allowing you to allocate entities for a world without locking or holding reference to the world.
1043/// This is especially useful in async contexts.
1044#[derive(Clone)]
1045pub struct RemoteAllocator {
1046    shared: Arc<SharedAllocator>,
1047}
1048
1049impl RemoteAllocator {
1050    /// Creates a new [`RemoteAllocator`] with the provided [`Allocator`] source.
1051    /// If the source is ever destroyed, [`Self::alloc`] will yield garbage values.
1052    /// Be sure to use [`Self::is_closed`] to determine if it is safe to use these entities.
1053    pub(super) fn new(source: &Allocator) -> Self {
1054        Self {
1055            shared: source.shared.clone(),
1056        }
1057    }
1058
1059    /// Returns whether or not this [`RemoteAllocator`] is connected to this source [`Allocator`].
1060    pub(super) fn is_connected_to(&self, source: &Allocator) -> bool {
1061        Arc::ptr_eq(&self.shared, &source.shared)
1062    }
1063
1064    /// Allocates an entity remotely.
1065    ///
1066    /// This comes with a major downside:
1067    /// Because this does not hold reference to the world, the world may be cleared or destroyed before you get a chance to use the result.
1068    /// If that happens, these entities will be garbage!
1069    /// They will not be unique in the world anymore and you should not spawn them!
1070    /// Before using the returned values in the world, first check that it is ok with [`EntityAllocator::has_remote_allocator`](super::EntityAllocator::has_remote_allocator).
1071    #[inline]
1072    pub fn alloc(&self) -> Entity {
1073        self.shared.remote_alloc()
1074    }
1075
1076    /// Returns whether or not this [`RemoteAllocator`] is still connected to its source [`EntityAllocator`](super::EntityAllocator).
1077    ///
1078    /// Note that this could close immediately after the function returns false, so be careful.
1079    /// The best way to ensure that does not happen is to only trust the returned value while holding a reference to the world
1080    /// and to ensure it is the right world through [`EntityAllocator::has_remote_allocator`](super::EntityAllocator::has_remote_allocator).
1081    ///
1082    /// This is generally best used as a diagnostic.
1083    /// [`EntityAllocator::has_remote_allocator`](super::EntityAllocator::has_remote_allocator) is a better check for correctness.
1084    pub fn is_closed(&self) -> bool {
1085        self.shared.is_closed()
1086    }
1087}
1088
1089#[cfg(test)]
1090mod tests {
1091    use super::*;
1092    use alloc::vec;
1093
1094    /// Ensure the total capacity of [`OwnedBuffer`] is `u32::MAX + 1`.
1095    #[test]
1096    fn chunk_capacity_sums() {
1097        let total: u64 = (0..FreeBuffer::NUM_CHUNKS)
1098            .map(FreeBuffer::capacity_of_chunk)
1099            .map(|x| x as u64)
1100            .sum();
1101        // The last 2 won't be used, but that's ok.
1102        // Keeping them powers of 2 makes things faster.
1103        let expected = u32::MAX as u64 + 1;
1104        assert_eq!(total, expected);
1105    }
1106
1107    /// Ensure [`OwnedBuffer`] can be properly indexed
1108    #[test]
1109    fn chunk_indexing() {
1110        let to_test = vec![
1111            (0, (0, 0, 512)), // index 0 cap = 512
1112            (1, (0, 1, 512)),
1113            (256, (0, 256, 512)),
1114            (511, (0, 511, 512)),
1115            (512, (1, 0, 512)), // index 1 cap = 512
1116            (1023, (1, 511, 512)),
1117            (1024, (2, 0, 1024)), // index 2 cap = 1024
1118            (1025, (2, 1, 1024)),
1119            (2047, (2, 1023, 1024)),
1120            (2048, (3, 0, 2048)), // index 3 cap = 2048
1121            (4095, (3, 2047, 2048)),
1122            (4096, (4, 0, 4096)), // index 3 cap = 4096
1123        ];
1124
1125        for (input, output) in to_test {
1126            assert_eq!(FreeBuffer::index_info(input), output);
1127        }
1128    }
1129
1130    #[test]
1131    fn buffer_len_encoding() {
1132        let len = FreeCount::new_zero_len();
1133        assert_eq!(len.state(Ordering::Relaxed).length(), 0);
1134        assert_eq!(len.pop_for_state(200, Ordering::Relaxed).length(), 0);
1135        len.set_state_risky(
1136            FreeCountState::new_zero_len().with_length(5),
1137            Ordering::Relaxed,
1138        );
1139        assert_eq!(len.pop_for_state(2, Ordering::Relaxed).length(), 5);
1140        assert_eq!(len.pop_for_state(2, Ordering::Relaxed).length(), 3);
1141        assert_eq!(len.pop_for_state(2, Ordering::Relaxed).length(), 1);
1142        assert_eq!(len.pop_for_state(2, Ordering::Relaxed).length(), 0);
1143    }
1144
1145    #[test]
1146    fn uniqueness() {
1147        let mut entities = Vec::with_capacity(2000);
1148        let mut allocator = Allocator::new();
1149        entities.extend(allocator.alloc_many(1000));
1150
1151        let pre_len = entities.len();
1152        entities.dedup();
1153        assert_eq!(pre_len, entities.len());
1154
1155        for e in entities.drain(..) {
1156            allocator.free(e);
1157        }
1158
1159        entities.extend(allocator.alloc_many(500));
1160        for _ in 0..1000 {
1161            entities.push(allocator.alloc());
1162        }
1163        entities.extend(allocator.alloc_many(500));
1164
1165        let pre_len = entities.len();
1166        entities.dedup();
1167        assert_eq!(pre_len, entities.len());
1168    }
1169
1170    /// Bevy's allocator doesn't make guarantees about what order entities will be allocated in.
1171    /// This test just exists to make sure allocations don't step on each other's toes.
1172    #[test]
1173    fn allocation_order_correctness() {
1174        let mut allocator = Allocator::new();
1175        let e0 = allocator.alloc();
1176        let e1 = allocator.alloc();
1177        let e2 = allocator.alloc();
1178        let e3 = allocator.alloc();
1179        allocator.free(e0);
1180        allocator.free(e1);
1181        allocator.free(e2);
1182        allocator.free(e3);
1183        allocator.flush_freed();
1184
1185        let r0 = allocator.alloc();
1186        let mut many = allocator.alloc_many(2);
1187        let r1 = many.next().unwrap();
1188        let r2 = many.next().unwrap();
1189        assert!(many.next().is_none());
1190        drop(many);
1191        let r3 = allocator.alloc();
1192
1193        assert_eq!(r0, e3);
1194        assert_eq!(r1, e1);
1195        assert_eq!(r2, e2);
1196        assert_eq!(r3, e0);
1197    }
1198}