I am still quite new to the advanced topics in rust, but for context, I am trying to implement a generic quadtree in rust.
With the method find_mut(&mut self,x,y) I want to traverse the quadtree to find the lowermost subtree containing that coordinate and return a mutable reference of it.
Quadtree Struct
pub struct QuadTree<T> {
x: i32,
y: i32,
dx: i32,
dy: i32,
leaf: bool,
subtrees: [Option<Box<Self>>; 4],
value: Option<T>,
}
Methods and functions
fn find_mut(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
let mut current = self;
loop {
// If we've arrived at a leaf return it as Ok
if current.leaf { // First borrow occurs here for some reason
return Ok(current);
}
// Getting the subtree that contains our coordinate
match current.mut_subtree_at(x, y) {
// Go a level deeper
Some(child) => current = child,
// Return an Err containing the lowest subtree that is sadly not a leaf
None => return Err(current),
}
}
}
fn subtree_id<'a>(&'a self, x: i32, y: i32) -> usize {
let mut child_id = 0;
if x >= self.x {
child_id += 1;
}
if y >= self.y {
child_id += 2;
}
child_id
}
#[inline(always)]
fn mut_subtree_at(&mut self, x: i32, y: i32) -> Option<&mut Self> {
self.subtrees[self.subtree_id(x, y)].as_deref_mut()
}
Error
error[E0499]: cannot borrow `*current` as mutable more than once at a time
--> src/quadtree.rs:128:36
|
115 | fn find_mut(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
| - let's call the lifetime of this reference `'1`
...
121 | return Ok(current);
| ----------- returning this value requires that `*current` is borrowed for `'1`
...
124 | match current.mut_subtree_at(x, y) {
| ---------------------------- first mutable borrow occurs here
...
128 | None => return Err(current),
| ^^^^^^^ second mutable borrow occurs here
How would you approach this problem. I am missing something about the way borrowing mutable references and lifetimes work?
While not ideal, here is a recursive version that compiles, but requires querying
mut_subtree_attwice:To my understanding this works because
.is_some()returns abool, which is an owned value and therefore Rust can prove that at the time ofErr(self)no reference is held toselfany more.It seems that the same principle also works for the iterative solution:
For more performance (meaning, if you don't want to call
mut_subtree_attwice), you would have to override the borrow checker as this is obviously a false positive.Luckily, there is the
polonius-the-crabcrate that is written for specifically the problem you ran into and hides the unsafe code in a safe and reliable manner.Here is my first working version using
polonius-the-crab:or this version, which is a little easier to understand as it uses polonius' macros: