pub struct OpaquePool { /* private fields */ }Expand description
A pinned object pool of unbounded size that accepts objects of different types as long as they match a specific memory layout.
The pool returns a Pooled<T> for each inserted value, which acts as a super-powered
pointer that can be copied and cloned freely. Each handle provides direct access to the
inserted item via a pointer.
§Out of band access
The collection does not create or keep references to the memory blocks. The only way to access
the contents of the collection is via unsafe code by using the pointer from a Pooled<T>.
The collection does not create or maintain any & shared or &mut exclusive references to
the items it contains, except when explicitly called to operate on an item (e.g. remove()
implies exclusive access).
§Resource usage
The collection automatically grows as items are added. To reduce memory usage after items have
been removed, use the shrink_to_fit() method to release unused capacity.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let mut pool = OpaquePool::builder().layout_of::<u32>().build();
// Insert a value and get a handle.
// SAFETY: u32 matches the layout used to create the pool.
let pooled = unsafe { pool.insert(42u32) };
// Read from the memory.
// SAFETY: The pointer is valid and the memory contains the value we just inserted.
let value = unsafe { pooled.ptr().read() };
assert_eq!(value, 42);
// Remove the value from the pool. This invalidates the pointer and drops the value.
pool.remove(pooled);Implementations§
Source§impl OpaquePool
impl OpaquePool
Sourcepub fn builder() -> OpaquePoolBuilder
pub fn builder() -> OpaquePoolBuilder
Creates a builder for configuring and constructing an OpaquePool.
This how you can create an OpaquePool. You must specify an item memory layout
using either .layout() or .layout_of::<T>() before calling .build().
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
// Create a pool for storing u64 values using explicit layout.
let layout = Layout::new::<u64>();
let pool = OpaquePool::builder().layout(layout).build();
assert_eq!(pool.len(), 0);
assert!(pool.is_empty());
assert_eq!(pool.item_layout(), layout);
// Create a pool for storing u32 values using type-based layout.
let pool = OpaquePool::builder().layout_of::<u32>().build();Sourcepub fn item_layout(&self) -> Layout
pub fn item_layout(&self) -> Layout
Returns the memory layout used by items in this pool.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let layout = Layout::new::<u128>();
let pool = OpaquePool::builder().layout(layout).build();
assert_eq!(pool.item_layout(), layout);
assert_eq!(pool.item_layout().size(), std::mem::size_of::<u128>());Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
The number of values that have been inserted into the pool.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let mut pool = OpaquePool::builder().layout_of::<i32>().build();
assert_eq!(pool.len(), 0);
// SAFETY: i32 matches the layout used to create the pool.
let pooled1 = unsafe { pool.insert(1i32) };
assert_eq!(pool.len(), 1);
// SAFETY: i32 matches the layout used to create the pool.
let pooled2 = unsafe { pool.insert(2i32) };
assert_eq!(pool.len(), 2);
pool.remove(pooled1);
assert_eq!(pool.len(), 1);Sourcepub fn capacity(&self) -> usize
pub fn capacity(&self) -> usize
The number of values the pool can accommodate without additional resource allocation.
This is the total capacity, including any existing items. The capacity will grow
automatically when insert() is called and insufficient capacity is available.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let mut pool = OpaquePool::builder().layout_of::<u8>().build();
// New pool starts with zero capacity.
assert_eq!(pool.capacity(), 0);
// Inserting values may increase capacity.
// SAFETY: u8 matches the layout used to create the pool.
let pooled = unsafe { pool.insert(42u8) };
assert!(pool.capacity() > 0);
assert!(pool.capacity() >= pool.len());Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Whether the pool has no inserted values.
An empty pool may still be holding unused memory capacity.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let mut pool = OpaquePool::builder().layout_of::<u16>().build();
assert!(pool.is_empty());
// SAFETY: u16 matches the layout used to create the pool.
let pooled = unsafe { pool.insert(42u16) };
assert!(!pool.is_empty());
pool.remove(pooled);
assert!(pool.is_empty());Sourcepub fn reserve(&mut self, additional: usize)
pub fn reserve(&mut self, additional: usize)
Reserves capacity for at least additional more items to be inserted in the pool.
The pool may reserve more space to speculatively avoid frequent reallocations.
After calling reserve, capacity will be greater than or equal to
self.len() + additional. Does nothing if capacity is already sufficient.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let mut pool = OpaquePool::builder().layout_of::<u32>().build();
// Reserve space for 10 more items
pool.reserve(10);
assert!(pool.capacity() >= 10);
// SAFETY: u32 matches the layout used to create the pool.
let pooled = unsafe { pool.insert(42u32) };
// Reserve additional space on top of existing items
pool.reserve(5);
assert!(pool.capacity() >= pool.len() + 5);Sourcepub fn shrink_to_fit(&mut self)
pub fn shrink_to_fit(&mut self)
Shrinks the pool’s memory usage by dropping unused capacity.
This method reduces the pool’s memory footprint by removing unused capacity where possible. Items currently in the pool are preserved.
The pool’s capacity may be reduced, but all existing handles remain valid.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let mut pool = OpaquePool::builder().layout_of::<u32>().build();
// Insert some items to create slabs
// SAFETY: u32 matches the layout used to create the pool.
let pooled1 = unsafe { pool.insert(1u32) };
// SAFETY: u32 matches the layout used to create the pool.
let pooled2 = unsafe { pool.insert(2u32) };
let initial_capacity = pool.capacity();
// Remove all items
pool.remove(pooled1);
pool.remove(pooled2);
// Capacity remains the same until we shrink
assert_eq!(pool.capacity(), initial_capacity);
// Shrink to fit reduces capacity
pool.shrink_to_fit();
assert!(pool.capacity() <= initial_capacity);Sourcepub unsafe fn insert<T>(&mut self, value: T) -> Pooled<T>
pub unsafe fn insert<T>(&mut self, value: T) -> Pooled<T>
Inserts a value into the pool and returns a handle that acts as the key and supplies a pointer to the item.
The returned Pooled<T> provides direct access to the memory via Pooled::ptr().
Accessing this pointer from unsafe code is the only way to use the inserted value.
The Pooled<T> may be returned to the pool via remove() to free the memory and
drop the value. Behavior of the pool if dropped when non-empty is determined
by the pool’s drop policy.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let mut pool = OpaquePool::builder().layout_of::<u64>().build();
// Insert a value.
// SAFETY: u64 matches the layout used to create the pool.
let pooled = unsafe { pool.insert(0xDEADBEEF_CAFEBABEu64) };
// Read data back.
// SAFETY: The pointer is valid for u64 reads/writes and we have exclusive access.
let value = unsafe { pooled.ptr().read() };
assert_eq!(value, 0xDEADBEEF_CAFEBABE);
// Write a new value into the item.
// SAFETY: The pointer is valid for u64 reads/writes and we have exclusive access.
unsafe {
pooled.ptr().write(0xBEEFCAFE_DEADBEEFu64);
}§Panics
In debug builds, panics if the layout of T does not match the pool’s item layout.
§Safety
The caller must ensure that the layout of T matches the pool’s item layout.
In debug builds, this is checked with an assertion.
Sourcepub fn remove<T>(&mut self, pooled: Pooled<T>)
pub fn remove<T>(&mut self, pooled: Pooled<T>)
Removes a value previously inserted into the pool.
The Pooled<T> is consumed by this operation and cannot be used afterward.
The value is dropped and the memory becomes available for future insertions.
There is no way to remove an item from the pool without dropping it.
§Example
use std::alloc::Layout;
use opaque_pool::OpaquePool;
let mut pool = OpaquePool::builder().layout_of::<i32>().build();
// SAFETY: i32 matches the layout used to create the pool.
let pooled = unsafe { pool.insert(42i32) };
assert_eq!(pool.len(), 1);
// Remove the value.
pool.remove(pooled);
assert_eq!(pool.len(), 0);
assert!(pool.is_empty());§Panics
Panics if the handle is not associated with this pool.