Skip to main content

Arena

Struct Arena 

Source
pub struct Arena<T> { /* private fields */ }
Expand description

A typed arena that allocates values and hands back stable Id handles.

Arena<T> is the allocation floor a tree of nodes is built on. Allocate a value with alloc and you get an Id<T> — a small, Copy, type-tagged handle that stays valid for the life of the arena. Resolve it back to the value with get. Values are never freed individually; the whole arena is released at once when it is dropped, which is the allocation pattern an AST or IR wants — many nodes allocated forward during a pass, none removed, all gone together at the end.

The handle, not a raw pointer, is the stable address: storing an Id<T> in one node to point at another is how a tree is wired, and the handle keeps resolving to the same value no matter how many later allocations grow the arena.

§Examples

use arena_lang::Arena;

// A tiny expression tree, wired by handle.
enum Expr {
    Int(i64),
    Add(arena_lang::Id<Expr>, arena_lang::Id<Expr>),
}

let mut arena = Arena::new();
let one = arena.alloc(Expr::Int(1));
let two = arena.alloc(Expr::Int(2));
let sum = arena.alloc(Expr::Add(one, two));

// The parent's handles still resolve after it was itself allocated.
match arena.get(sum) {
    Some(Expr::Add(l, r)) => {
        assert!(matches!(arena.get(*l), Some(Expr::Int(1))));
        assert!(matches!(arena.get(*r), Some(Expr::Int(2))));
    }
    _ => unreachable!(),
}

Implementations§

Source§

impl<T> Arena<T>

Source

pub const fn new() -> Arena<T>

Creates an empty arena. const, so it can initialise a static.

No allocation happens until the first value is added.

§Examples
use arena_lang::Arena;

let arena: Arena<u32> = Arena::new();
assert!(arena.is_empty());
Source

pub fn with_capacity(capacity: usize) -> Arena<T>

Creates an empty arena with room for capacity values preallocated.

A hint only: it reserves backing storage so the first capacity allocations do not reallocate. Sizing it to the expected node count — for instance, a multiple of the token count of the source — keeps allocation on the flat part of the cost curve.

§Examples
use arena_lang::Arena;

let mut arena = Arena::with_capacity(3);
let ids = [arena.alloc('a'), arena.alloc('b'), arena.alloc('c')];
assert_eq!(arena.len(), 3);
assert_eq!(ids.map(|id| *arena.get(id).unwrap()), ['a', 'b', 'c']);
Source

pub fn reserve(&mut self, additional: usize)

Reserves capacity for at least additional more values.

Use it before a burst of allocations whose count is known, to fold what would be several incremental growths into one.

§Examples
use arena_lang::Arena;

let mut arena: Arena<u8> = Arena::new();
arena.reserve(128);
assert!(arena.capacity() >= 128);
Source

pub fn alloc(&mut self, value: T) -> Id<T>

Allocates value and returns a stable Id handle to it.

This is the hot path. The handle is valid for the life of the arena and keeps resolving to this value through every later allocation.

§Panics

Panics only if the arena has already allocated u32::MAX values and cannot represent another handle — a ceiling of more than four billion live nodes, unreachable for any real tree. Use try_alloc for an explicit non-panicking path.

§Examples
use arena_lang::Arena;

let mut arena = Arena::new();
let id = arena.alloc(42);
assert_eq!(arena.get(id), Some(&42));
Source

pub fn try_alloc(&mut self, value: T) -> Result<Id<T>, ArenaError>

Allocates value, returning its Id or an error if the arena is full.

The non-panicking counterpart to alloc: identical on success, but it returns ArenaError::CapacityExhausted instead of panicking at the u32::MAX-value ceiling. Prefer it when building a tree from untrusted input whose size you do not control.

§Errors

Returns ArenaError::CapacityExhausted when the arena’s slot space is full. The arena is left unchanged.

§Examples
use arena_lang::Arena;

let mut arena = Arena::new();
let id = arena.try_alloc("ok")?;
assert_eq!(arena.get(id), Some(&"ok"));
Source

pub fn get(&self, id: Id<T>) -> Option<&T>

Borrows the value behind id, or None if the handle does not name a live value in this arena.

Resolution is a direct slot lookup, not a search. A handle from this arena always resolves; the None case guards against an out-of-range handle, so resolving one never reads outside the arena’s storage.

§Examples
use arena_lang::Arena;

let mut arena = Arena::new();
let id = arena.alloc(vec![1, 2, 3]);
assert_eq!(arena.get(id).map(Vec::len), Some(3));
Source

pub fn get_mut(&mut self, id: Id<T>) -> Option<&mut T>

Mutably borrows the value behind id, or None if the handle does not name a live value in this arena.

Useful for back-patching a node after it is allocated — resolving a forward reference, or filling in a parent link once the parent exists.

§Examples
use arena_lang::Arena;

let mut arena = Arena::new();
let id = arena.alloc(0_u32);
if let Some(slot) = arena.get_mut(id) {
    *slot = 99;
}
assert_eq!(arena.get(id), Some(&99));
Source

pub fn contains(&self, id: Id<T>) -> bool

Returns true if id names a live value in this arena.

§Examples
use arena_lang::Arena;

let mut arena = Arena::new();
let id = arena.alloc("x");
assert!(arena.contains(id));
Source

pub fn len(&self) -> usize

Returns the number of values in the arena.

§Examples
use arena_lang::Arena;

let mut arena = Arena::new();
assert_eq!(arena.len(), 0);
arena.alloc(());
assert_eq!(arena.len(), 1);
Source

pub fn is_empty(&self) -> bool

Returns true if the arena holds no values.

§Examples
use arena_lang::Arena;

let mut arena = Arena::new();
assert!(arena.is_empty());
arena.alloc(());
assert!(!arena.is_empty());
Source

pub fn capacity(&self) -> usize

Returns the number of values the arena can hold before it must grow.

§Examples
use arena_lang::Arena;

let arena: Arena<u64> = Arena::with_capacity(8);
assert!(arena.capacity() >= 8);
Source

pub fn iter(&self) -> impl Iterator<Item = (Id<T>, &T)>

Iterates over every value in the arena, paired with its handle.

Values are visited in allocation order — the order their ids were minted — so the first pair is (Id 0, first value). Useful for a pass that walks all nodes without following the tree’s edges.

§Examples
use arena_lang::Arena;

let mut arena = Arena::new();
let a = arena.alloc(10);
let b = arena.alloc(20);

// Allocation order, with the matching handles.
let pairs: Vec<_> = arena.iter().collect();
assert_eq!(pairs, vec![(a, &10), (b, &20)]);

let total: i32 = arena.iter().map(|(_, v)| *v).sum();
assert_eq!(total, 30);

Trait Implementations§

Source§

impl<T> Debug for Arena<T>

Source§

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

Shows the arena’s size, not its contents — an arena can hold millions of nodes, and dumping them all is rarely what a debug print wants. This also keeps Arena<T>: Debug free of any T: Debug bound.

Source§

impl<T> Default for Arena<T>

Source§

fn default() -> Arena<T>

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<T> Freeze for Arena<T>

§

impl<T> RefUnwindSafe for Arena<T>
where T: RefUnwindSafe,

§

impl<T> Send for Arena<T>
where T: Send,

§

impl<T> Sync for Arena<T>
where T: Sync,

§

impl<T> Unpin for Arena<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for Arena<T>

§

impl<T> UnwindSafe for Arena<T>
where T: 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.