Self-referential Rust structs using arena allocation
Thu, Aug 14 2025
A lot of ink has been spilled on the topic of self-referential structures in Rust. I won't pile on.
I stumbled across a different pattern for achieving them in this github repo.
I found it useful for creating a tree of nodes that refer to each other after parsing some HTML.
Arena Allocator + std::cell::Cell
:
pub struct Node<'a> {
kind: NodeKind<'a>,
parent: Cell<Option<&'a Node<'a>>>,
previous_sibling: Cell<Option<&'a Node<'a>>>,
next_sibling: Cell<Option<&'a Node<'a>>>,
first_child: Cell<Option<&'a Node<'a>>>,
last_child: Cell<Option<&'a Node<'a>>>,
}
... where 'a
is the lifetime of the arena allocator0 you are using.0
bumpalo has served me well.
This works because:
- The compiler knows the size of the struct. All the
Node
s are behind a&
indirection. - Cell allows you to retrieve and mutate values from behind shared references (i.e.
&
) as long as the value isCopy
.&Node
isCopy
because it's a pointer. - Parsing functions can receive an arena allocator as argument, allocate their nodes into the arena and return references to nodes whose lifetime is tied to the arena.
For my use case:
- It is much better than using indices instead of references because you don't have to pass around the the list of objects everywhere.
- It is much better than
Rc<RefCell<...>>
because you don't have to worry about overlappingborrow_mut()
calls.
It feels like alien tech 👾