Generational indices, typed arenas, interned strings, bump allocation. Zero unsafe leakage into user code.
Allocator-aware Rust normally means juggling three or four crates: one for slab storage, one for handle stability, one for string interning, plus a bump arena for short-lived scratch. arena-lib collects those primitives behind a single, safe, REPS-disciplined surface so you can move fast without paying for it later.
Designed around four guarantees:
- Typed arenas — one backing allocation per element type, predictable layout, cache-friendly traversal.
- Generational indices — stable handles that catch use-after-free without reference counting.
- String interning — O(1) equality and compact storage for repeated identifiers.
- Bump allocation — short-lived scratch regions that reset in constant time.
Every public path is safe Rust. unsafe lives only in measured, documented internals — never in your call sites.
Status: v1.0.0 — stable. API frozen. Within the 1.x line, only purely additive changes are permitted (new methods on existing types, new variants on the
#[non_exhaustive]Errorenum). Anything that would break a 1.x caller is out of scope until a hypothetical 2.0.
Add the crate to your Cargo.toml:
[dependencies]
arena-lib = "1"End-to-end use of every primitive:
use arena_lib::prelude::*;
fn main() {
// Generational arena — stable handles, use-after-free detection.
let mut arena: Arena<&'static str> = Arena::with_capacity(8);
let alice = arena.insert("alice");
let bob = arena.insert("bob");
assert_eq!(arena.get(alice), Some(&"alice"));
// String interner — O(1) equality on repeated identifiers.
let mut interner = Interner::with_capacity(8);
let id_a = interner.intern("user:alice");
let id_b = interner.intern("user:alice");
assert_eq!(id_a, id_b);
// Bump arena — fast scratch, grows on demand, O(1) reset.
let bump = Bump::with_capacity(64);
let scratch = bump.alloc([0_u8; 16]);
assert_eq!(scratch.len(), 16);
// Drop arena — same ergonomics but runs destructors on drop.
let owned = DropArena::<String>::new();
let s = owned.alloc(String::from("freed when `owned` is dropped"));
assert!(s.contains("dropped"));
// Removing a slot invalidates its handle without touching the rest.
assert_eq!(arena.remove(alice), Some("alice"));
assert!(arena.get(alice).is_none());
assert!(arena.get(bob).is_some());
}See docs/API.md for the full reference, including the planned 1.0 surface.
- REPS governs every decision. See REPS.md.
- MSRV: Rust 1.85.
- Edition: 2024.
- Cross-platform: Linux, macOS, Windows.
Dual-licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.