std/pool
A fixed-size block pool allocator: one malloc (plus a generation table and a free-index stack, both sized at construction) and then O(1) alloc and free with no syscalls and no further heap allocation. That is the pattern safety-critical code uses to avoid dynamic allocation after startup.
A block is never an address. alloc returns a PoolBlock, a generational handle in the std/arena Handle<T> style: it carries the pool's identity and the block's generation, so a handle kept past free or reset, or one from another pool, is rejected instead of reaching whatever block now lives in that slot. The bytes are lent as a bounds-checked &[u8] / &mut [u8] for the duration of a closure, and a fresh block is zeroed.
from "std/pool" import { Pool, PoolBlock }Example
var pool = Pool.new(64, 16)! // 16 blocks of 64 bytes, one malloc
let block = pool.alloc()!
print(pool.available()) // 15
let ok = pool.write(block, (bytes: &mut [u8]) => {
bytes[0] = 42
})
print(pool.with(block, (bytes: &[u8]): u8 => bytes[0]) ?? 0) // 42
print(pool.free(block)) // true
print(pool.valid(block)) // false: the handle went staleAPI reference
Pool
pub struct PoolA pool of blockCount blocks of blockSize bytes each.
_gens holds one generation per block, same encoding as std/arena: positive is live (and equals the generation of the one valid handle), negative is free (its magnitude is the generation the next alloc will publish), zero is retired because the counter hit i32 max. _freeList is a stack of free indices sized to blockCount at init, so push and pop never reallocate.
Pool.alloc
fn Pool.alloc(self: &mut Pool): Result<PoolBlock>Take a free block, zeroed, and return the handle naming it. Errs when the pool is exhausted.
Pool.available
fn Pool.available(self: &Pool): i64Pool.blockSize
fn Pool.blockSize(self: &Pool): i64Bytes per block.
Pool.empty
fn Pool.empty(self: &Pool): boolPool.free
fn Pool.free(self: &mut Pool, b: PoolBlock): boolRelease b. Every copy of b goes stale. False when b was already stale or belongs to another pool.
Pool.full
fn Pool.full(self: &Pool): boolPool.live
fn Pool.live(self: &Pool): i64Restate poolLive's preconditions (Pool has no struct invariant): without them the wrapper can't discharge the callee's requires, so its own ensures result >= 0 is unbacked.
Pool.new
fn Pool.new(size: i64, count: i64): Result<Pool>A pool of count blocks of size bytes, from one malloc. Errs on a non-positive size or count, or a total above 1 GB.
Pool.read
fn Pool.read(self: &Pool, b: PoolBlock, f: (&[u8]) => void): boolwith for a closure that returns nothing. False, and f is not called, when b is stale.
Pool.reset
fn Pool.reset(self: &mut Pool): voidFree every block at once; every outstanding handle goes stale.
Pool.valid
fn Pool.valid(self: &Pool, b: PoolBlock): boolWhether b names a live block of THIS pool.
Pool.with
fn Pool.with<R>(self: &Pool, b: PoolBlock, f: (&[u8]) => R): Option<R>Lend the block's bytes to f and return what it returns. None, and f is not called, when b is stale. Indexing past blockSize traps like any slice.
Pool.withMut
fn Pool.withMut<R>(self: &mut Pool, b: PoolBlock, f: (&mut [u8]) => R): Option<R>with with a mutable view: writes land in the block.
Pool.write
fn Pool.write(self: &mut Pool, b: PoolBlock, f: (&mut [u8]) => void): boolwithMut for a closure that returns nothing. False, and f is not called, when b is stale.
PoolBlock
pub struct PoolBlockA copyable token naming one block of one Pool. Get it from pool.alloc() and pass it back to with / withMut / free. Every field is private, so a handle cannot be built or edited outside this file; the only way to hold one is to have been given it by alloc.