Skip to content

Instantly share code, notes, and snippets.

@AndrewGaspar
Created April 30, 2020 15:14
Show Gist options
  • Save AndrewGaspar/80798097e496d418e43621c138ecec7e to your computer and use it in GitHub Desktop.
Save AndrewGaspar/80798097e496d418e43621c138ecec7e to your computer and use it in GitHub Desktop.
Global Arena Rust
use std::cell::RefCell;
// `generational_arena` is a special type of arena that allows elements to be recycled, and the
// handles allocated from the arena do not hold a borrow on the arena. The handles are later used to
// retrieve concrete borrows on the arena temporarily. The check for live-ness is essentially
// performed at runtime, rather than being checked by the borrow checker.
use generational_arena::{Arena, Index};
// Allocate `ARENA` at global/thread scope. The arena is wrapped in a RefCell so we can get
// runtime-checked mutable borrows of the arena.
thread_local! {
static ARENA: RefCell<Arena<Node>> = RefCell::new(Arena::new());
}
/// The `Node` construct. Notice that its children are stored as `Index`es. This means you have to
/// handle these `Index` handles to the `ARENA` to get back a temporary borrow of a `Node` object.
#[derive(Debug, Default)]
struct Node {
left: Option<Index>,
right: Option<Index>,
}
/// Simple main function that builds a tree with a depth of 3
fn main() {
let root = alloc_node();
build_tree(root, 3);
}
/// Allocates a new Node. Panics if there are outstanding borrows of `ARENA`.
fn alloc_node() -> Index {
// With `thread_local`, we can only access the global within the context of the `with` callback.
ARENA.with(|a| {
// `borrow_mut` performs a runtime check. It borrows the arena temporarily, inserts a node,
// and returns the `Index`. `Index` does not store a borrow, and therefore does not retain
// exclusive access to the Arena. However, this does mean that the borrow checking is,
// essentially, deferred to runtime later - it's on the programmer to make sure they line
// this all up correctly.
a.borrow_mut().insert(Node::default())
})
}
/// Builds a tree of nodes to `depth` starting with `node`.
fn build_tree(node: Index, depth: u32) {
if depth == 0 {
return;
}
let left = alloc_node();
let right = alloc_node();
build_tree(left, depth - 1);
build_tree(right, depth - 1);
// Here we update the child nodes. Again, the values are `Index`es - essentially handles to
// retrieve the actual nodes at a later time.
ARENA.with(|a| {
let mut a = a.borrow_mut();
let a = a.get_mut(node).unwrap();
a.left = Some(left);
a.right = Some(right);
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment