Skip to main content

PoolAllocator

Struct PoolAllocator 

Source
pub struct PoolAllocator<A: Allocator> { /* private fields */ }
Expand description

A lock-free, fixed-size block allocator backed by a single pre-allocated slab.

At construction time the slab is divided into equal-sized blocks whose size is at least max(item_layout.size(), size_of::<FreeNode>()) and whose alignment is at least max(item_layout.align(), align_of::<FreeNode>()). All blocks are linked into a free-list; allocation atomically pops the head; deallocation atomically pushes to the head.

§Constraints

  • Allocations larger than block_layout.size() or with stricter alignment than block_layout.align() are rejected (return None).
  • The pool has a fixed capacity; once all blocks are in use, allocation returns None.

§Thread Safety

PoolAllocator is Sync + Send when the backing allocator is Sync + Send. Both alloc and dealloc use lock-free CAS loops.

Implementations§

Source§

impl<A: Allocator> PoolAllocator<A>

Source

pub fn new(backing: A, item_layout: Layout, capacity: usize) -> Option<Self>

Creates a new pool with capacity blocks sized for item_layout.

The effective block size is max(item_layout.size(), size_of::<FreeNode>()) padded to the effective alignment. Returns None if the backing allocator fails to allocate the slab.

§Arguments
  • backing — Allocator used to allocate and later free the slab.
  • item_layout — Layout of the items that will be stored in the pool.
  • capacity — Maximum number of live allocations the pool can hold.
Source

pub fn typed<T>(backing: A, capacity: usize) -> Option<Self>

Convenience constructor that derives item_layout from the type T.

Equivalent to PoolAllocator::new(backing, Layout::new::<T>(), capacity).

Examples found in repository?
examples/pool_string.rs (line 9)
6fn main() {
7    let sys = SystemAllocator;
8
9    let pool = PoolAllocator::typed::<[u8; 128]>(&sys, 5).unwrap();
10
11    let mut log = ExString::new(&pool);
12    write!(log, "Status: {}, Code: {}", "OK", 200).unwrap();
13
14    println!("Log message: {}", log.as_str());
15    println!("Slots left in pool: {}", pool.free_count());
16}
More examples
Hide additional examples
examples/full.rs (line 39)
9fn main() {
10    let sys = CountingAllocator::new(SystemAllocator);
11    
12    println!("=== ExBox & SystemAllocator ===");
13    {
14        let b = ExBox::new(42, &sys).expect("Failed to alloc Box");
15        println!("Box value: {}", *b);
16    }
17    
18    let stats = sys.stats();
19    println!("Allocated: {} bytes", stats.bytes_allocated);
20    println!("Deallocated: {} bytes", stats.bytes_freed);
21    println!("Live bytes: {}\n", stats.bytes_live);
22
23    println!("=== ExVec & Arena (Linear Allocation) ===");
24    {
25        let arena = ArenaAllocator::new(&sys);
26        
27        let mut v = ExVec::new(&arena);
28        for i in 0..5 {
29            v.push(i * 10);
30        }
31        println!("Vec: {:?}", v.as_slice());
32        
33        arena.reset();
34        println!("Arena reset performed");
35    }
36
37    println!("\n=== ExString & Pool (Fixed Size Blocks) ===");
38    {
39        let pool = PoolAllocator::typed::<[u8; 64]>(&sys, 10)
40            .expect("Failed to create Pool");
41        
42        let mut s = ExString::new(&pool);
43        s.push_str("Hello from ZigZag!");
44        
45        println!("String in Pool: {}", s.as_str());
46        println!("Pool free slots: {}", pool.free_count());
47    }
48
49    println!("\n=== Final Global Stats ===");
50    let final_stats = sys.stats();
51    println!("Total count of alloc() calls: {}", final_stats.allocs);
52    println!("Total count of dealloc() calls: {}", final_stats.deallocs);
53    println!("Total bytes allocated: {}", final_stats.bytes_allocated);
54    println!("Total bytes freed: {}", final_stats.bytes_freed);
55    println!("Current leak/live size: {} bytes", final_stats.bytes_live);
56}
Source

pub fn capacity(&self) -> usize

Returns the maximum number of blocks this pool can provide simultaneously.

Source

pub fn block_layout(&self) -> Layout

Returns the padded layout of a single pool block.

Source

pub fn free_count(&self) -> usize

Returns the number of blocks currently on the free-list.

This traverses the entire free-list and is O(free_count), so use only for diagnostics / debugging.

Examples found in repository?
examples/pool_string.rs (line 15)
6fn main() {
7    let sys = SystemAllocator;
8
9    let pool = PoolAllocator::typed::<[u8; 128]>(&sys, 5).unwrap();
10
11    let mut log = ExString::new(&pool);
12    write!(log, "Status: {}, Code: {}", "OK", 200).unwrap();
13
14    println!("Log message: {}", log.as_str());
15    println!("Slots left in pool: {}", pool.free_count());
16}
More examples
Hide additional examples
examples/full.rs (line 46)
9fn main() {
10    let sys = CountingAllocator::new(SystemAllocator);
11    
12    println!("=== ExBox & SystemAllocator ===");
13    {
14        let b = ExBox::new(42, &sys).expect("Failed to alloc Box");
15        println!("Box value: {}", *b);
16    }
17    
18    let stats = sys.stats();
19    println!("Allocated: {} bytes", stats.bytes_allocated);
20    println!("Deallocated: {} bytes", stats.bytes_freed);
21    println!("Live bytes: {}\n", stats.bytes_live);
22
23    println!("=== ExVec & Arena (Linear Allocation) ===");
24    {
25        let arena = ArenaAllocator::new(&sys);
26        
27        let mut v = ExVec::new(&arena);
28        for i in 0..5 {
29            v.push(i * 10);
30        }
31        println!("Vec: {:?}", v.as_slice());
32        
33        arena.reset();
34        println!("Arena reset performed");
35    }
36
37    println!("\n=== ExString & Pool (Fixed Size Blocks) ===");
38    {
39        let pool = PoolAllocator::typed::<[u8; 64]>(&sys, 10)
40            .expect("Failed to create Pool");
41        
42        let mut s = ExString::new(&pool);
43        s.push_str("Hello from ZigZag!");
44        
45        println!("String in Pool: {}", s.as_str());
46        println!("Pool free slots: {}", pool.free_count());
47    }
48
49    println!("\n=== Final Global Stats ===");
50    let final_stats = sys.stats();
51    println!("Total count of alloc() calls: {}", final_stats.allocs);
52    println!("Total count of dealloc() calls: {}", final_stats.deallocs);
53    println!("Total bytes allocated: {}", final_stats.bytes_allocated);
54    println!("Total bytes freed: {}", final_stats.bytes_freed);
55    println!("Current leak/live size: {} bytes", final_stats.bytes_live);
56}
Source

pub unsafe fn dealloc_zeroed(&self, ptr: NonNull<u8>)

Zeroes the block at ptr and returns it to the pool.

Useful when blocks may contain sensitive data.

§Safety
  • ptr must have been obtained from this pool via alloc.
  • ptr must not be used after this call.
Source

pub unsafe fn wipe_slab(&self)

Zeroes the entire slab without modifying the free-list.

Intended for secure teardown. Do not call while any block is in use.

§Safety

All blocks — including live ones — will have their bytes set to zero. Any live references into the pool will read garbage (all zeros).

Trait Implementations§

Source§

impl<A: Allocator> Allocator for PoolAllocator<A>

Source§

unsafe fn alloc(&self, layout: Layout) -> Option<NonNull<u8>>

Pops one block from the free-list and returns a pointer to it.

Returns None if the pool is exhausted or if layout is too large / too strictly aligned for the pool’s block size.

§Safety
  • layout.size() must be ≤ block_layout.size().
  • layout.align() must be ≤ block_layout.align().
  • The caller must eventually call dealloc with the same pointer (and any layout whose size and align fit the pool).
Source§

unsafe fn dealloc(&self, ptr: NonNull<u8>, _layout: Layout)

Pushes a block back onto the free-list.

The _layout parameter is ignored; what matters is that ptr belongs to this pool’s slab.

§Safety
  • ptr must have been obtained from this pool via alloc.
  • ptr must not be accessed after this call.
  • Calling dealloc twice with the same pointer is undefined behaviour (double-free corrupts the free-list).
Source§

impl<A: Allocator> Drop for PoolAllocator<A>

Source§

fn drop(&mut self)

Returns the entire slab to the backing allocator.

Source§

impl<A: Allocator + Send> Send for PoolAllocator<A>

Source§

impl<A: Allocator + Sync> Sync for PoolAllocator<A>

Auto Trait Implementations§

§

impl<A> !Freeze for PoolAllocator<A>

§

impl<A> RefUnwindSafe for PoolAllocator<A>
where A: RefUnwindSafe,

§

impl<A> Unpin for PoolAllocator<A>
where A: Unpin,

§

impl<A> UnsafeUnpin for PoolAllocator<A>
where A: UnsafeUnpin,

§

impl<A> UnwindSafe for PoolAllocator<A>
where A: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.