Repository: bevyengine/bevy
File: crates/bevy_ecs/src/entity/remote_allocator.rs (Rust)

Code before:

    /// Frees the entity allowing it to be reused.
    #[inline]
    pub(super) fn free(&mut self, entity: Entity) {
        if self.quick_free.is_full() {
            self.flush_freed();
        }
        // SAFETY: The `ArrayVec` is not full or has just been cleared.
        unsafe {
            self.quick_free.push_unchecked(entity);
        }
    }

    /// Allocates `count` entities in an iterator.
    #[inline]
    pub(super) fn alloc_many(&self, count: u32) -> AllocEntitiesIterator<'_> {
        // SAFETY: `free` takes `&mut self`, and this lifetime is captured by the iterator.
        unsafe { self.shared.alloc_many(count) }
    }

    /// Frees the entities allowing them to be reused.
    #[inline]
    pub(super) fn free_many(&mut self, entities: &[Entity]) {
        // SAFETY: We have `&mut self`.
        unsafe {
            self.shared.free.free(entities);
        }
    }
}

impl Drop for Allocator {
    fn drop(&mut self) {
        self.shared.close();
    }
}

impl core::fmt::Debug for Allocator {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct(core::any::type_name::<Self>())
            .field("total_indices", &self.total_entity_indices())
            .field("total_free", &self.num_free())
            .finish()
    }
}

/// An [`Iterator`] returning a sequence of [`Entity`] values from an [`Allocator`].
///
/// **NOTE:** Dropping will leak the remaining entities!
pub(super) struct AllocEntitiesIterator<'a> {
    new: AllocUniqueEntityIndexIterator,
    reused: FreeBufferIterator<'a>,

Review comment (performance):
Is it worth trying to use `quick_free` here if there is capacity?  Something like

```rust
if self.quick_free.try_extend_from_slice(entities).is_err() {
    self.shared.free.free(entities);
}
```

?

Or maybe you'd even want to `extend()` then `flush_freed()` then `extend()` sometimes, if `entities.len() < quick_free.capacity()`.  That could avoid the need for the "This is slower than `free` when used with very small slices (dozens of entities) " case in the docs.  

Code after:
            self.shared.free.free(self.local_free.as_slice());
        }
        self.local_free.clear();
    }

    /// Frees the entity allowing it to be reused.
    #[inline]
    pub(super) fn free(&mut self, entity: Entity) {
        if self.local_free.is_full() {
            self.flush_freed();
        }
        // SAFETY: The `ArrayVec` is not full or has just been cleared.
        unsafe {
            self.local_free.push_unchecked(entity);
        }
    }

    /// Allocates `count` entities in an iterator.
    #[inline]
    pub(super) fn alloc_many(&self, count: u32) -> AllocEntitiesIterator<'_> {
        // SAFETY: `free` takes `&mut self`, and this lifetime is captured by the iterator.
        unsafe { self.shared.alloc_many(count) }
    }

    /// Frees the entities allowing them to be reused.
    #[inline]
    pub(super) fn free_many(&mut self, entities: &[Entity]) {
        if self.local_free.try_extend_from_slice(entities).is_err() {
            // SAFETY: We have `&mut self`.
            unsafe {
                self.shared.free.free(entities);
            }
        }
    }
}

impl Drop for Allocator {
    fn drop(&mut self) {
        self.shared.close();
    }
}

impl core::fmt::Debug for Allocator {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct(core::any::type_name::<Self>())
            .field("total_indices", &self.total_entity_indices())
            .field("total_free", &self.num_free())
            .finish()
    }
}