Ключом было использование гибридного решения Arena / Cell. Родители и дети теперь являются просто ссылками на узлы, но изменчивость включается с помощью Cell
и RefCell
:
struct Node<'a> {
arena: &'a Arena<Node<'a>>,
parent: Cell<Option<&'a Node<'a>>>,
children: RefCell<Vec<&'a Node<'a>>>,
}
impl<'a> Node<'a> {
fn add_child(&'a self) {
let child = new_node(self.arena);
child.parent.set(Some(self));
self.children.borrow_mut().push(child);
}
fn get_child(&'a self, i: usize) -> &'a Node<'a> {
self.children.borrow()[i]
}
fn get_parent(&'a self) -> &'a Node<'a> {
self.parent.get().expect("No Parent!")
}
}
Теперь Arena владеет каждым узлом вместо родителей, владеющих своими детьми (это только деталь реализации и не мешает никакой функциональности). В результате нет необходимости передавать родителя на add_child
:
let arena: Arena<Node> = Arena::new();
let top_node = new_node(&arena);
top_node.add_child();
let mut ptr = top_node.get_child(0);
ptr.add_child();
ptr = ptr.get_child(0);
ptr = ptr.get_parent();
Решение использует следующую вспомогательную функцию для запуска и сохранения владения на Arena:
fn new_node<'a>(arena: &'a Arena<Node<'a>>) -> &'a mut Node<'a> {
arena.alloc(Node {
arena: arena,
parent: Cell::new(None),
children: RefCell::new(vec![]),
})
}