Skip to main content

euv_engine/pool/
struct.rs

1/// A reusable object pool with a free-list that preserves memory across
2/// release/acquire cycles.
3///
4/// The pool keeps two disjoint collections of `T`: the free list of values
5/// the pool owns and is ready to hand out again, and the count of values
6/// currently checked out and tracked as active. Releasing a value never
7/// destroys it — the caller's value is moved back onto the free list and
8/// reused by the next acquire, so a per-frame spawn/despawn cycle stops
9/// paying for `Vec` growth and reallocation.
10///
11/// ## Checkout order
12///
13/// The free list is **LIFO**: [`ObjectPool::acquire`] pops the most recently
14/// released value. The most recently used value is therefore the next one
15/// handed out, which keeps a recycling workload on the hottest allocations
16/// instead of sweeping a cold list.
17///
18/// ## Why hand-written accessors
19///
20/// Lombok's `Data` derive is intentionally **not** applied here, matching the
21/// precedent set by [`Tween`](crate::Tween) and
22/// [`EngineCell`](crate::EngineCell): the derive does not propagate generic
23/// bounds, so deriving on `ObjectPool<T>` would constrain `T` in ways the
24/// pool must not constrain. The accessors below follow the same naming
25/// contract as the Lombok-generated ones (`get_*` / `get_mut_*` / `set_*`).
26pub struct ObjectPool<T> {
27    /// The number of values currently checked out of the pool.
28    ///
29    /// Tracked as a count rather than a `Vec<T>` because acquire hands the
30    /// value to the caller by move: the pool cannot also retain it without
31    /// requiring `T: Clone`, which the pool deliberately avoids so that
32    /// recycling a value never duplicates its allocation.
33    pub(crate) active: usize,
34    /// Values owned by the pool, ready to be handed out again.
35    pub(crate) free: Vec<T>,
36}