Search for Successor of BST node, "clone to satisfy borrow checker" disaster - rust

I am trying to implement a BST in Rust. My struct looks like this:
pub struct Node<T> {
key: T,
parent: Option<Box<Node<T>>>,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
I am working on a method for finding the successor of a current node. After a prolonged fight with the borrow checker, I made it work, but it now looks like this:
//If right node exists - successor is a min node in it.
//Else - go up a parent node. If parent is None, no successor.
//If origin was parent's left node - parent is a successor.
//Else - go up another level.
pub fn succ(&self) -> Option<Box<Node<T>>> {
match self.right {
Some(ref node) => Some(node.min()),
None => {
let mut origin = Box::new(self.clone()); //To match types
let mut parent = origin.parent.clone(); //`Node<T>` not a copy type
loop {
let parent_node = match parent.clone() {
Some(node) => node,
None => break,
};
let right_of_parent = match parent_node.clone().right {
Some(node) => node,
None => break,
};
if *origin != *right_of_parent {
break;
}
origin = parent_node;
parent = origin.parent.clone();
}
parent
}
}
}
If I remove all the .clone()s, the compiler starts crying with "partial moved value" and "cannot assign because borrowed" errors. Is there a way to make this code more idiomatic and less of a cloning hell?
UPD:
Wanted to post the solution I ended up with.
First of all, above code doesn't work, as the parent field contained not a reference, but a copy of a parent node. So in the end the question turned into "how to implement a reference to a parent node".
I considered the answer below, some books and relevant answers and in the end i came to conclusion that it don't worth it for a toy project that I didn't even plan to publish online. I've found not the most efficient, but definitely simpler solution - not to use parent reference at all.
I removed parent field from the structure above and created another structure:
pub struct Tree<T> {
root: Option<Box<Node<T>>>,
}
And now I search for parent from the root of the tree. My succ function now looks like this:
fn succ<'a>(&'a self, node: &'a Node<T>) -> Option<&Node<T>> {
match node.right {
Some(ref rnode) => rnode.min(),
None => {
let mut succ = None;
let mut root = self.root.as_ref();
loop {
root = match root {
Some(ref rootnode) => {
match node.key.cmp(&rootnode.key) {
Ordering::Less => {
succ = Some(&***rootnode);
rootnode.left.as_ref()
}
Ordering::Greater => rootnode.right.as_ref(),
Ordering::Equal => break,
}
}
None => break,
}
}
succ
}
}
}

Welcome to Rust and Stack Overflow!
The main issue here is Node definition:
pub struct Node<T> {
key: T,
parent: Option<Box<Node<T>>>,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
In Rust, Box<T> owns the value rather than being a pointer which can alias. You wouldn't be a able to create any non-trivial trees.
Instead of Box, you could try the reference counted Rc<T>. You can use Weak pointers for the parent links to avoid keeping them alive:
use std::rc::{Rc,Weak};
pub struct Node<T> {
key: T,
parent: Option<Weak<Node<T>>>,
left: Option<Rc<Node<T>>>,
right: Option<Rc<Node<T>>>,
}
Once this is sorted, you're not using references. Each time you do something like:
let mut parent = origin.parent; //.clone();
where in your version origin.parent is of type Option<Box<Node<T>>>, you're trying to move that Option field out of origin - hence why you had to add the clone() (which clones the node inside the Box, not just the pointer!). However, you don't really want to move out; you just want a reference to it, like:
let parent = &origin.parent;
Or do the None check at the same time:
match origin.parent {
Some(ref parent_ptr) => { ... },
None => { ... }
}
I hope this helps!

Related

How does ownership of variables work between iterations?

I am trying to learn rust and thought of implementing a linked list as a practice problem to understand Ownership/Borrow concepts and I am having a hard time.
The push method of LinkedList should work as:
t = 0 | root: None | push 5
t = 1 | root: { value: 5, next: None } | push 6
t = 2 | root: { value: 5, next: { value: 6, None } } |
Here's the code trying to do the same:
#[derive(Debug, Clone)]
struct Node {
value: u32,
next: Option<Box<Node>>,
}
impl Node {
fn new(value: u32) -> Node {
Node { value, next: None }
}
}
#[derive(Debug, Clone)]
struct LinkedList {
root: Option<Box<Node>>,
}
impl LinkedList {
fn new(node: Option<Box<Node>>) -> LinkedList {
LinkedList { root: node }
}
fn push(self, node: Option<Box<Node>>) {
let maybe_node = self.root;
loop {
match maybe_node {
Some(tail_node) => { // use of moved value. std::boxed::Box<Node> doesn't implement copy trait. --- (1)
if tail_node.next.is_none() {
tail_node.next = node; // tail_node is not mutable. --- (2)
break;
};
}
_ => (),
}
}
}
}
fn main() {
let mut node = Node::new(0);
let linked_list = LinkedList::new(Some(Box::new(node)));
for number in 1..5 {
node = Node::new(number);
linked_list.push(Some(Box::new(node))); // move occurs. Value moved here in a previous iteration --- (3)
}
println!("{:?}", linked_list);
}
I don't understand the "move occurs" errors (1, 3) it isn't clear to me where the value moved? It appears iterations are causing the ownership to change but I can't see how.
Also, the error (2) Is my implementation the best way?
In Rust there two ways is which ownership is handled, and that is either move semantic or borrow semantic. Here are some rules to go about understanding it.
The first rule is that each piece of data can have only a single owner at same time. If you assign some variable to some other variable, then you effectively move the data, and the data becomes owned by new owner.
The second rule is that if you have some data, which is owned by someone, but you would like to read it, then you can borrow it. Borrowing is essentially obtaining a reference to data, which is owned by someone else.
Now back to your problem. In your function declaration you have declared the first parameter as self
fn push(self, node: Option<Box<Node>>) {
let maybe_node = self.root;
loop {
match maybe_node {
Some(tail_node) => { // use of moved value. std::boxed::Box<Node> doesn't implement copy trait. --- (1)
if tail_node.next.is_none() {
tail_node.next = node; // tail_node is not mutable. --- (2)
break;
};
}
_ => (),
}
}
}
this essentially means that when you call your function you are taking the ownership of self, and thus you are invalidating any previous owner. What happens in the loop is that in the first iteration the value is moved into the function and is no longer owned by linked_list. In second iteration you again try to access the data, but it is no longer valid, since it was moved into the function.
To circumvent your problem you will need to declare your function as follows:
fn push(&mut self, node: Option<Box<Node>>) {
let maybe_node = self.root;
loop {
match maybe_node {
Some(tail_node) => { // use of moved value. std::boxed::Box<Node> doesn't implement copy trait. --- (1)
if tail_node.next.is_none() {
tail_node.next = node; // tail_node is not mutable. --- (2)
break;
};
}
_ => (),
}
}
}
With declaration above you are saying that you are borrowing self, and that you would like to make changes to it ( that is the reason we have &mut and not just & ).
For more details please refer to the chapter about ownership in Rust book.

Borrowed value does not live long enough when creating reference to parent node

I'm trying to learn Rust, and for that I decided to implement Depth First Search algorithm.
So far I have the following Node struct:
#[derive(Debug)]
pub struct Node<'a> {
parent: Option<&'a Node<'a>>,
position: crate::entities::Position,
}
As you can see every time I create a node there is a reference to its parent.
Now, I have the dfs algorithm:
pub fn dfs<'a>(maze: &crate::entities::Maze) -> Node<'static> {
let mut traversed = Vec::new();
let mut frontier = Vec::new();
let mut seen: HashSet<crate::entities::Position> = HashSet::new();
let parent = Node {
parent: None,
position: maze.start // position is just a holder for row and column
};
frontier.push(parent);
loop {
if frontier.is_empty() {
panic!("No solution found!")
}
let current: Node<'static> = frontier.pop().expect("There must be a node here");
let position = current.position;
if current.position == maze.exit {
break current;
} else {
if !seen.contains(&current.position) {
let neighbours = maze.get_neighbours(current.position).iter().map(|pos| Node {
parent: Some(&current), // this line is not compiling
position: *pos
}).collect::<Vec<Node>>();
frontier.append(&mut neighbours);
traversed.push(current);
}
}
seen.insert(position);
}
}
But I am getting a compile error:
27 | parent: Some(&current),
| ^^^^^^^ borrowed value does not live long enough
How can I fix that?
Your basic problem is you management of the nodes. Notice that a node is first created by the matrix, then put into the frontier and lastly moved into traversed. This means that you cannot use references to your nodes, since they might move, invalidating the reference.
The solution is to have a central store of node, and then using indices when referring to them. This of course, doesn't play nice with you implementation of Node, but you could change that to use indices instead of references to parents.

Can't do breadth-first search on a binary tree in Rust

I've implemented a binary tree in Rust as a learning project but failed to transverse it to print the tree in a breadth-first search fashion.
The issue is that I can't reassign the search queue (children) because it's borrowed and doesn't live long enough.
https://gist.github.com/varshard/3874803cd035e27facb67c59e89c3c1c#file-binary_tree-rs-L39
How can I correct this?
use std::fmt::Display;
type Branch<'a, T> = Option<Box<Node<'a, T>>>;
struct Node<'a, T: PartialOrd + Display> {
value: &'a T,
left: Branch<'a, T>,
right: Branch<'a, T>
}
impl<'a, T: PartialOrd + Display> Node<'a, T> {
fn insert(&mut self, value: &'a T) {
let target_node = if value > self.value { &mut self.right } else { &mut self.left };
match target_node {
Some(ref mut node) => node.insert(value),
None => {
let new_node = Node{ value: value, left: None, right: None};
*target_node = Some(Box::new(new_node))
}
}
}
fn display(&'a self) {
let mut children: Vec<Option<&Node<'a, T>>> = Vec::new();
children.push(Some(self));
while children.len() > 0 {
for child in &children {
match child {
Some(node) => {
print!("{} ", node.value);
},
None => {
print!(" ")
}
}
}
println!("");
// Error: children doesn't live long enough;
children = self.to_vec(&children);
}
}
fn to_vec(&self, nodes: &'a Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {
let mut children: Vec<Option<&Node<'a, T>>> = Vec::new();
for node_option in nodes {
match node_option {
Some(node) => {
match &node.left {
Some(left) => {
children.push(Some(left));
match &node.right {
Some(right) => {
children.push(Some(right));
},
None => {
children.push(None);
}
}
},
None => {
children.push(None);
match &node.right {
Some(right) => {
children.push(Some(right));
},
None => {
children.push(None);
}
}
}
}
},
None => {}
}
}
children
}
}
fn main() {
let root_val = 5;
let mut root = Node{ value: &root_val, left: None, right: None };
root.insert(&3);
root.insert(&4);
root.insert(&1);
root.insert(&6);
root.display();
}
Copying my answer from this reddit comment:
There's a way to directly fix your problem, but I think there are better options for making the code easier to write and understand. For the direct fix, you can make some lifetime adjustments. Instead of
fn to_vec(&self, nodes: &'a Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {
You need:
fn to_vec<'b>(&self, nodes: &Vec<Option<&'b Node<'a, T>>>) -> Vec<Option<&'b Node<'a, T>>>
What's the difference there? In the first case we're saying that nodes is a &'a Vec. That is, a borrow of a Vec that lives as long as the value references inside your tree. That's a long time to live, and it's what the compiler's getting angry about.
Now, if you just take the 'a off of that &Vec, the compiler complains about something else:
|
42 | fn to_vec(&self, nodes: &Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {
| ------------ -------------------------
| |
| this parameter and the return type are declared with different lifetimes...
...
76 | children
| ^^^^^^^^ ...but data from `nodes` is returned here
Maybe this is the error that pushed you to put the 'a on the &Vec in the first place. We need to solve it a different way. The important thing to understand here is that the return value doesn't contain references directly into the nodes vector, but it does contain copies of the nodes vector's contents, the &Node references. We need to tell the compiler that even though the nodes reference doesn't live very long, its contents do live longer. That's why we create the new lifetime 'b in my fix above.
This is objectively very confusing. Personally, I prefer to avoid solving these tricky problems, by just keeping things alive longer instead of reasoning about exactly how long they live. The source of the difficulty is that we're destroying the children vector on line 39. If we were able to keep it around, and just keep emptying it and refilling it, Rust would give us a much easier time. Have you considered using a std::collections::VecDeque instead of a Vec here? You could construct it once outside of your while-loop, and then you could pass &mut children around, without worrying very much about its lifetime. I think a queue is usually the go-to data structure for a breadth-first traversal, with new children added to the back, and the traversal itself reading from the front.

Rust: Implement AVL Tree and error: thread 'main' panicked at 'already borrowed: BorrowMutError'

I have the following tree structure:
use std::cell::RefCell;
use std::rc::Rc;
use std::cmp;
use std::cmp::Ordering;
type AVLTree<T> = Option<Rc<RefCell<TreeNode<T>>>>;
#[derive(Debug, PartialEq, Clone)]
struct TreeSet<T: Ord> {
root: AVLTree<T>,
}
impl<T: Ord> TreeSet<T> {
fn new() -> Self {
Self {
root: None
}
}
fn insert(&mut self, value: T) -> bool {
let current_tree = &mut self.root;
while let Some(current_node) = current_tree {
let node_key = &current_node.borrow().key;
match node_key.cmp(&value) {
Ordering::Less => { let current_tree = &mut current_node.borrow_mut().right; },
Ordering::Equal => {
return false;
}
Ordering::Greater => { let current_tree = &mut current_node.borrow_mut().left; },
}
}
*current_tree = Some(Rc::new(RefCell::new(TreeNode {
key: value,
left: None,
right: None,
parent: None
})));
true
}
}
#[derive(Clone, Debug, PartialEq)]
struct TreeNode<T: Ord> {
pub key: T,
pub parent: AVLTree<T>,
left: AVLTree<T>,
right: AVLTree<T>,
}
fn main() {
let mut new_avl_tree: TreeSet<u32> = TreeSet::new();
new_avl_tree.insert(3);
new_avl_tree.insert(5);
println!("Tree: {:#?}", &new_avl_tree);
}
Building with cargo build is fine, but when I run cargo run, I got the below error:
thread 'main' panicked at 'already borrowed: BorrowMutError', src\libcore\result.rs:1165:5
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace. error: process didn't
exit successfully: target\debug\avl-tree.exe (exit code: 101)
If i just call insert(3), it will be fine and my tree gets printed correctly. However, if I insert(5) after insert(3), I will get that error.
How do I fix that?
Manually implementing data structures such as linked list, tree, graph are not task for novices, because of memory safety rules in language. I suggest you to read Too Many Linked Lists tutorial, which discusses how to implement safe and unsafe linked lists in Rust right way.
Also read about name shadowing.
Your error is that inside a cycle you try to borrow mutable something which is already borrowed as immutable.
let node_key = &current_node.borrow().key; // Borrow as immutable
match node_key.cmp(&value) {
Ordering::Less => { let current_tree = &mut current_node.borrow_mut().right; }, // Create a binding which will be immediately deleted and borrow as mutable.
And I recommend you to read Rust book to learn rust.
First let us correct your algorithm. The following lines are incorrect:
let current_tree = &mut current_node.borrow_mut().right;
...
let current_tree = &mut current_node.borrow_mut().left;
Both do not reassign a value to current_tree but create a new (unused) one (#Inline refers to it as Name shadowing). Remove the let and make current_tree mut.
Now we get a compiler error temporary value dropped while borrowed. Probably the compiler error message did mislead you. It tells you to use let to increase the lifetime, and this would be right if you used the result in the same scope, but no let can increase the lifetime beyond the scope.
The problem is that you cannot pass out a reference to a value owned by a loop (as current_node.borrow_mut.right). So it would be better to use current_tree as owned variable. Sadly this means that many clever tricks in your code will not work any more.
Another problem in the code is the multiple borrow problem (your original runtime warning is about this). You cannot call borrow() and borrow_mut() on the same RefCell without panic(that is the purpose of RefCell).
So after finding the problems in your code, I got interested in how I would write the code. And now that it is written, I thought it would be fair to share it:
fn insert(&mut self, value: T) -> bool {
if let None = self.root {
self.root = TreeSet::root(value);
return true;
}
let mut current_tree = self.root.clone();
while let Some(current_node) = current_tree {
let mut borrowed_node = current_node.borrow_mut();
match borrowed_node.key.cmp(&value) {
Ordering::Less => {
if let Some(next_node) = &borrowed_node.right {
current_tree = Some(next_node.clone());
} else {
borrowed_node.right = current_node.child(value);
return true;
}
}
Ordering::Equal => {
return false;
}
Ordering::Greater => {
if let Some(next_node) = &borrowed_node.left {
current_tree = Some(next_node.clone());
} else {
borrowed_node.left = current_node.child(value);
return true;
}
}
};
}
true
}
//...
trait NewChild<T: Ord> {
fn child(&self, value: T) -> AVLTree<T>;
}
impl<T: Ord> NewChild<T> for Rc<RefCell<TreeNode<T>>> {
fn child(&self, value: T) -> AVLTree<T> {
Some(Rc::new(RefCell::new(TreeNode {
key: value,
left: None,
right: None,
parent: Some(self.clone()),
})))
}
}
One will have to write the two methods child(value:T) and root(value:T) to make this compile.

"thread '<main>' has overflowed its stack" when constructing a large tree

I implemented a tree struct:
use std::collections::VecDeque;
use std::rc::{Rc, Weak};
use std::cell::RefCell;
struct A {
children: Option<VecDeque<Rc<RefCell<A>>>>
}
// I got thread '<main>' has overflowed its stack
fn main(){
let mut tree_stack: VecDeque<Rc<RefCell<A>>> = VecDeque::new();
// when num is 1000, everything works
for i in 0..100000 {
tree_stack.push_back(Rc::new(RefCell::new(A {children: None})));
}
println!("{:?}", "reach here means we are not out of mem");
loop {
if tree_stack.len() == 1 {break;}
let mut new_tree_node = Rc::new(RefCell::new(A {children: None}));
let mut tree_node_children: VecDeque<Rc<RefCell<A>>> = VecDeque::new();
// combine last two nodes to one new node
match tree_stack.pop_back() {
Some(x) => {
tree_node_children.push_front(x);
},
None => {}
}
match tree_stack.pop_back() {
Some(x) => {
tree_node_children.push_front(x);
},
None => {}
}
new_tree_node.borrow_mut().children = Some(tree_node_children);
tree_stack.push_back(new_tree_node);
}
}
Playpen link
But it crashes with
thread '<main>' has overflowed its stack
How do I fix that?
The problem that you are experiencing is because you have a giant linked-list of nodes. When that list is dropped, the first element tries to free all the members of the struct first. That means that the second element does the same, and so on, until the end of the list. This means that you will have a call stack that is proportional to the number of elements in your list!
Here's a small reproduction:
struct A {
children: Option<Box<A>>
}
fn main() {
let mut list = A { children: None };
for _ in 0..1_000_000 {
list = A { children: Some(Box::new(list)) };
}
}
And here's how you would fix it:
impl Drop for A {
fn drop(&mut self) {
if let Some(mut child) = self.children.take() {
while let Some(next) = child.children.take() {
child = next;
}
}
}
}
This code overrides the default recursive drop implementation with an iterative one. It rips the children out of the node, replacing it with a terminal item (None). It then allows the node to drop normally, but there will be no recursive calls.
The code is complicated a bit because we can't drop ourselves, so we need to do a little two-step dance to ignore the first item and then eat up all the children.
See also:
How can I swap in a new value for a field in a mutable reference to a structure?
How do I move out of a struct field that is an Option?

Resources