MTB::Entity: Address-stable, interior-mutable Slab allocator
中文版请见: README-zh.md
⚠️ Notes
- This allocator is experimental and unstable: for each semver 0.x.y, each
.ychange causes API breaking changes and each.xchange causes rewrite or redesign of this project. - Not thoroughly tested; may contain memory-safety issues. Use with care.
- Single-threaded only; no plans for multithreading.
- If you don’t specifically need interior mutability, prefer the
slabcrate for performance and safety.
Introduction
While building Remusys, needing a mutable reference to allocate with slab::Slab made some optimizations awkward. This allocator is chunked and address-stable, and it lets you allocate while reading existing elements.
use *;
/// You can use `#[entity_id]` to create an opaque ID wrapper bound to a fixed policy.
/// If the allocator type is too verbose, specify an alias via `allocator_type`.
Core types
EntityAlloc<E, P>— allocator managing chunks and elements.PtrID<E, P>— pointer-style ID; internally a raw pointer. Fast but unsafe to misuse.IndexedID<E, P>— index-style ID; chunk index + in-chunk index. Safer but slower.IEntityAllocID<E, P>— trait for converting betweenPtrIDandIndexedID.IPoliciedID— trait binding an ID to its object type and allocator type (policy included).PtrID<E, P>,IndexedID<E, P>and macro-generated wrappers implement this.IDBoundAlloc<I>— convenience alias forEntityAlloc<<I as IPoliciedID>::ObjectT, <I as IPoliciedID>::PolicyT>.
Allocation policies
Policies are compile-time constants on P:
AllocPolicy128— 128 elements per chunk (single-level bitmap)AllocPolicy256— 256 elements per chunk (single-level bitmap)AllocPolicy512— 512 elements per chunk (single-level bitmap)AllocPolicy1024— 1024 elements per chunk (two-level bitmap)AllocPolicy2048— 2048 elements per chunk (two-level bitmap)AllocPolicy4096— 4096 elements per chunk (two-level bitmap)
Examples with an Inst entity:
let alloc_128: = new;
let alloc_256: = new;
let alloc_512: = new;
let alloc_1024: = new;
let alloc_2048: = new;
let alloc_4096: = new;
let id_128 = alloc_128.allocate ; // PtrID<Inst, AllocPolicy128>
let id_256 = alloc_256.allocate ; // PtrID<Inst, AllocPolicy256>
let id_512 = alloc_512.allocate ; // PtrID<Inst, AllocPolicy512>
let id_1024 = alloc_1024.allocate; // PtrID<Inst, AllocPolicy1024>
let id_2048 = alloc_2048.allocate; // PtrID<Inst, AllocPolicy2048>
let id_4096 = alloc_4096.allocate; // PtrID<Inst, AllocPolicy4096>
The policy on the ID helps prevent accidentally using an ID with an allocator of the wrong capacity.
Custom ID wrappers with #[entity_id]
This attribute generates a newtype wrapper around a backend ID (PtrID<Object, Policy> or IndexedID<Object, Policy>) bound to a fixed policy and, optionally, an allocator type alias.
Example:
// Pointer backend (default)
// Index backend (safer, slower)
Options:
policy = NNN | PolicyNNN | AllocPolicyNNN— bind to a specific policy; NNN in [128, 4096].allocator_type = AliasName— emit a type alias for the allocator (type AliasName = EntityAlloc<Object, Policy>). Visibility follows the annotated type.backend = ptr | index— choose pointer or index ID backend (default:ptr).opaque— make the inner backend ID field crate-visible instead of public, reducing accidental exposure.
ID constraints
Library data structures rely on the IPoliciedID trait to describe "an ID tied to a particular object and allocator type." Raw PtrID<E, P>, IndexedID<E, P> and any #[entity_id] wrappers implement it, so you can use containers with any backend.
Note: Wrapper types intentionally do not expose allocation/free convenience methods; allocation stays at the raw layer (allocate_ptr, allocate_index or IEntityAllocID::allocate_from).
Containers
Built on IPoliciedID, the crate provides internally-mutable containers:
EntityList<I>— doubly-linked list. Typical for instruction/basic-block lists. Internally mutable; no&mut allocneeded, but misuse can corrupt relationships.EntityRingList<I>— ring list. Useful for def-use sets; attach has no signals, detach does.
Note: In v0.2, container generics flipped from the object type ObjT to the constrained ID type I.
Safety notice
This crate uses unsafe code without formal verification. It is neither general-purpose nor guaranteed safe. Prefer slab unless you truly need these semantics.