Background
I have a simple structure that's actually a full binary tree, but I'm using petgraph because I got stuck implementing all the traversals on a binary tree by myself (due to issues with borrow checker).
use petgraph::Graph;
pub struct Layout<'a> {
graph: LayoutGraph<'a>,
}
pub type LayoutGraph<'a> = Graph<NodeLabel<'a>, ()>;
pub enum NodeLabel<'a> {
Internal(SliceDirection),
Leaf(&'a RgbImage),
}
To make working with the layout easier, I created another data structure:
pub struct LayoutNode<'a> {
index: NodeIndex,
layout: &'a Layout<'a>,
}
impl LayoutNode<'_> {
pub fn node_label(&self) -> &NodeLabel { //…
pub fn children(&self) -> Option<(LayoutNode, LayoutNode)> { //…
pub fn parent(&self) -> Option<LayoutNode> { //…
}
LayoutNode mostly proxies those calls to Layout and Layout then operates on Graph.
Problem
Now, what I want to achieve is that given an arbitrary LayoutNode, I want to return its ancestors – essentially looping a call to .parent()
until it returns None
. I tried to implement an iterator, but that didn't work out because my Item
would need to have a named lifetime and that isn't supported right now. A streaming iterator doesn't work for the same reason.
So then I was like, alright, let's just collect them into a VecDeque
. But I just can't seem to find a way for the borrow checker to let me do that.
let leaf_node = layout.leaf_nodes().next().unwrap();
let mut iter = leaf_node;
let mut ancestors = VecDeque::new();
while let Some(node) = iter.parent() {
ancestors.push_front(node);
iter = node;
}
This doesn't work because
error[E0506]: cannot assign to `iter` because it is borrowed
--> src/main.rs:26:5
|
24 | while let Some(node) = iter.parent() {
| ------------- borrow of `iter` occurs here
25 | ancestors.push_front(node);
26 | iter = node;
| ^^^^^^^^^^^
| |
| assignment to borrowed `iter` occurs here
| borrow later used here
error[E0382]: use of moved value: `node`
--> src/main.rs:26:12
|
24 | while let Some(node) = iter.parent() {
| ---- move occurs because `node` has type `LayoutNode<'_>`, which does not implement the `Copy` trait
25 | ancestors.push_front(node);
| ---- value moved here
26 | iter = node;
| ^^^^ value used here after move
Given a Layout that exists in the same scope, I don't see a reason why I couldn't collect all those ancestry nodes into a vec.
How could I grab a parent of a node without borrowing the node itself? Or is there another way to achieve what I'm trying to do?
I feel like maybe I should use something like Rc, but thinking about ownership management still gives me a lot of trouble.