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>
impl<T> Arena<T>
Sourcepub const fn new() -> Arena<T>
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());Sourcepub fn with_capacity(capacity: usize) -> Arena<T>
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']);Sourcepub fn reserve(&mut self, additional: usize)
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);Sourcepub fn alloc(&mut self, value: T) -> Id<T>
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));Sourcepub fn try_alloc(&mut self, value: T) -> Result<Id<T>, ArenaError>
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"));Sourcepub fn get(&self, id: Id<T>) -> Option<&T>
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));Sourcepub fn get_mut(&mut self, id: Id<T>) -> Option<&mut T>
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));Sourcepub fn contains(&self, id: Id<T>) -> bool
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));Sourcepub fn len(&self) -> usize
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);Sourcepub fn is_empty(&self) -> bool
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());Sourcepub fn capacity(&self) -> usize
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);Sourcepub fn iter(&self) -> impl Iterator<Item = (Id<T>, &T)>
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);