pub struct Arena<'a, T: Slot> { /* private fields */ }Expand description
A sharded collection of fixed-size records in one contiguous byte pool, sorted by key prefix within each shard.
See the crate-level documentation for the philosophy and the module documentation for the chain/split mechanics. Highlights:
- all state is
pool+ three small arrays — persisting the arena is amemcpyof defined bytes; - every operation touches O(1) pages: a short chain walk (one first-key peek per step), then binary search and shifts inside one 4 KiB page;
- capacity is bounded only by
ArenaCfg::max_bytes— full pages split, emptied pages are recycled through a free-list; Arenadeliberately implements neitherClonenorPartialEq: pages are allocated uninitialized (the measured wasm optimization), and a byte-wise clone/compare would read the uninitialized tails.
Implementations§
Source§impl<'a, T: Slot> Arena<'a, T>
impl<'a, T: Slot> Arena<'a, T>
Sourcepub fn new(cfg: ArenaCfg) -> Result<Self, Error>
pub fn new(cfg: ArenaCfg) -> Result<Self, Error>
Creates an empty arena.
§Errors
Error::BadSlotunless1 <= T::KEY_LEN <= T::SIZE <= PAGE_BYTES;Error::BadShardCountunlesscfg.shardsis a non-zero power of two.
Sourcepub const fn slots_per_page() -> usize
pub const fn slots_per_page() -> usize
Number of slots one page holds for this slot size (at least 1).
Sourcepub fn pool_bytes(&self) -> usize
pub fn pool_bytes(&self) -> usize
Bytes currently allocated in the page pool (including recycled free-list pages — the pool never shrinks; emptied pages are reused).
Sourcepub fn insert(&mut self, value: &T) -> Result<bool, Error>
pub fn insert(&mut self, value: &T) -> Result<bool, Error>
Inserts a record, keeping its shard’s chain sorted by key prefix.
Returns Ok(false) if a record with the same key prefix already
exists (the arena is a map keyed by prefix; existing payload is left
untouched — use Arena::payload_mut to update in place). A full
target page splits in half — inserts never fail on page capacity.
§Errors
Error::CapacityExceeded if a needed page allocation would cross
ArenaCfg::max_bytes.
Sourcepub fn get(&self, key: &[u8]) -> Option<T>
pub fn get(&self, key: &[u8]) -> Option<T>
Returns the record with the given key prefix, if present.
§Panics
Panics if key.len() != T::KEY_LEN (a caller bug, not a data
condition — mirrors slice indexing).
Sourcepub fn get_slot(&self, key: &[u8]) -> Option<&[u8]>
pub fn get_slot(&self, key: &[u8]) -> Option<&[u8]>
Returns the raw bytes of the record with the given key prefix.
§Panics
Panics if key.len() != T::KEY_LEN.
Sourcepub fn payload_mut(&mut self, key: &[u8]) -> Option<&mut [u8]>
pub fn payload_mut(&mut self, key: &[u8]) -> Option<&mut [u8]>
Returns a mutable view of the record’s payload (the bytes after the key prefix), for in-place updates.
The key prefix itself is not reachable through this method — sorted order cannot be corrupted by construction, which is why this is safe to expose at all.
§Panics
Panics if key.len() != T::KEY_LEN.
Sourcepub fn remove(&mut self, key: &[u8]) -> bool
pub fn remove(&mut self, key: &[u8]) -> bool
Removes the record with the given key prefix. Returns true if it
existed. A page emptied by the removal is unlinked from its chain and
recycled through the free-list.
§Panics
Panics if key.len() != T::KEY_LEN.
Sourcepub fn iter(&self) -> Iter<'_, T> ⓘ
pub fn iter(&self) -> Iter<'_, T> ⓘ
Iterates all records shard by shard, following each shard’s chain.
In ShardMode::Ordered the shard index order equals key order and
chains are range-partitioned, so this yields globally ascending
keys. In ShardMode::Uniform the global order is unspecified
(each shard is still internally sorted).
Sourcepub fn range<'s>(&'s self, from: &[u8], to: &'s [u8]) -> Range<'s, T>
pub fn range<'s>(&'s self, from: &[u8], to: &'s [u8]) -> Range<'s, T>
Iterates records whose key prefix lies in [from, to) — from
inclusive, to exclusive — in ascending key order.
Only meaningful when shard order equals key order, hence restricted
to ShardMode::Ordered.
§Panics
Panics if the arena is in ShardMode::Uniform, or if either bound’s
length differs from T::KEY_LEN.
Sourcepub fn dump_meta(&self, out: &mut Vec<u8>)
pub fn dump_meta(&self, out: &mut Vec<u8>)
Appends the arena’s metadata section to out.
Layout (all little-endian): [shards u32][pages u32][free_head u32] [total u64][mode u8][reserved 3], then heads (shards × u32),
next (pages × u32), counts (pages × u16). Together with
Arena::dump_pool this is the complete state; both dumps are
canonical — dump → Arena::load → dump reproduces identical
bytes.
Sourcepub fn dump_pool(&self, out: &mut Vec<u8>)
pub fn dump_pool(&self, out: &mut Vec<u8>)
Appends the arena’s pool section to out.
Each page contributes its initialized prefix (counts[page] × SIZE bytes) followed by zero padding to PAGE_BYTES: the
uninitialized page tails (see Arena::insert internals) are
never read, and zero-filling them makes the image canonical and
leak-free.
Sourcepub fn load(cfg: ArenaCfg, meta: &[u8], pool: &[u8]) -> Result<Self, Error>
pub fn load(cfg: ArenaCfg, meta: &[u8], pool: &[u8]) -> Result<Self, Error>
Rebuilds an arena from its two dumped sections.
The input is untrusted: every metadata invariant is checked
before adoption and any inconsistency returns
Error::Corrupt — this method never panics on arbitrary bytes.
Cost is O(pages) on top of the pool copy:
- exact section lengths;
cfgagreement (shards, mode); - per-page slot counts within
PAGE_BYTES / SIZE; - every page reachable exactly once — shard chains and the free-list are walked with a visited bitmap (no cycles, no shared or orphan pages); chain pages are non-empty, free pages empty;
- chain pages ascend by key range and sit in the shard their first key maps to; the record total matches the page counts.
Slot content is not validated beyond the per-page first/last key reads — record payloads are semantically validated lazily by the owning engine.
§Errors
Error::BadSlot / Error::BadShardCount for an invalid cfg
(same gates as Arena::new); Error::Corrupt for any image
inconsistency.
Sourcepub fn load_borrowed(
cfg: ArenaCfg,
meta: &[u8],
pool: &'a [u8],
) -> Result<Self, Error>
pub fn load_borrowed( cfg: ArenaCfg, meta: &[u8], pool: &'a [u8], ) -> Result<Self, Error>
Rebuilds an arena that borrows its page pool from a longer-lived
buffer (a memory-mapped snapshot) instead of copying it.
Validation is identical to Arena::load — it reads each page’s
first and last keys, so it touches one OS page per arena page (the
key-order check needs them), but no pool byte is copied.
§Errors
Same as Arena::load.
Sourcepub fn load_overlay(
cfg: ArenaCfg,
meta: &[u8],
pool: &'a [u8],
) -> Result<Self, Error>
pub fn load_overlay( cfg: ArenaCfg, meta: &[u8], pool: &'a [u8], ) -> Result<Self, Error>
Opens an arena over a borrowed base for the overlay write path: the
base pages are mapped read-only, and the first write to any base page
copies just that page into owned storage (per-page copy-on-write, see
Paged), while pages grown after open live in an owned
tail. Unlike Arena::load_borrowed the returned arena is fully
mutable — inserts, removals and splits work — yet the borrowed base is
never cloned as a whole and never mutated, so a memory-mapped database
can be written to while resident only in the pages it actually touches.
Validation is identical to Arena::load.
§Errors
Same as Arena::load.