Skip to main content

Arena

Struct Arena 

Source
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 a memcpy of 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;
  • Arena deliberately implements neither Clone nor PartialEq: 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>

Source

pub fn new(cfg: ArenaCfg) -> Result<Self, Error>

Creates an empty arena.

§Errors
Source

pub const fn slots_per_page() -> usize

Number of slots one page holds for this slot size (at least 1).

Source

pub fn len(&self) -> usize

Total number of records.

Source

pub fn is_empty(&self) -> bool

true when the arena holds no records.

Source

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).

Source

pub fn cfg(&self) -> &ArenaCfg

The configuration this arena was created with.

Source

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.

Source

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).

Source

pub fn contains(&self, key: &[u8]) -> bool

true if a record with the given key prefix exists.

§Panics

Panics if key.len() != T::KEY_LEN.

Source

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.

Source

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.

Source

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.

Source

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).

Source

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.

Source

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.

Source

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.

Source

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; cfg agreement (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.

Source

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.

Source

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.

Trait Implementations§

Source§

impl<T: Slot> Debug for Arena<'_, T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Summary only — dumping the pool would both flood output and read uninitialized page tails.

Source§

impl<'a, T: Slot> IntoIterator for &'a Arena<'a, T>

Source§

type Item = T

The type of the elements being iterated over.
Source§

type IntoIter = Iter<'a, T>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more

Auto Trait Implementations§

§

impl<'a, T> Freeze for Arena<'a, T>

§

impl<'a, T> RefUnwindSafe for Arena<'a, T>

§

impl<'a, T> Send for Arena<'a, T>

§

impl<'a, T> Sync for Arena<'a, T>

§

impl<'a, T> Unpin for Arena<'a, T>

§

impl<'a, T> UnsafeUnpin for Arena<'a, T>

§

impl<'a, T> UnwindSafe for Arena<'a, T>

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.