0

I've been playing around with implementing red-black trees from CLRS in Rust. The code (as it currently stands) is as follows:

use std::cmp::PartialOrd;
use std::fmt::Display;

struct RedBlackNode<'a, T> {
    elem: T,
    colour: bool,
    left: Option<&'a mut RedBlackNode<'a, T>>,
    right: Option<&'a mut RedBlackNode<'a, T>>,
    parent: Option<&'a mut RedBlackNode<'a, T>>,
}

impl<'a, T> RedBlackNode<'a, T> {
    fn new(elem: T) -> Self {
        RedBlackNode::<T> {
            elem: elem,
            colour: false,
            left: None,
            right: None,
            parent: None,
        }
    }
}

impl<T: PartialEq> PartialEq for RedBlackNode<'_, T> {
    fn eq(&self, other: &Self) -> bool {
        self.elem == other.elem
    }
}

pub struct RedBlackTree<'a, T> {
    root: Option<RedBlackNode<'a, T>>,
}

impl<'a, T: PartialOrd> RedBlackTree<'a, T> {
    pub fn new() -> Self {
        RedBlackTree::<T> { root: None }
    }

    pub fn add(&mut self, elem: T) {
        let z: RedBlackNode<'a, T> = RedBlackNode::new(elem);

        let mut y: Option<&'a mut RedBlackNode<'a, T>> = None;
        let mut x: Option<&'a mut RedBlackNode<'a, T>> = self.root.as_mut();

        while !x.is_none() {
            y = x;

            if z.elem < x.unwrap().elem {
                x = x.unwrap().left;
            } else {
                x = x.unwrap().right;
            }
        }

        z.parent = y;

        if y.is_none() {
            self.root = Some(z);
        } else if z.elem < y.unwrap().elem {
            y.unwrap().left = Some(&mut z);
        } else {
            y.unwrap().right = Some(&mut z);
        }

        z.left = None;
        z.right = None;
        z.colour = true;

        self.insert_fixup(&mut z);
    }

    fn left_rotate(&mut self, z: &mut RedBlackNode<'a, T>) {
        unimplemented!();
    }

    fn right_rotate(&mut self, z: &mut RedBlackNode<'a, T>) {
        unimplemented!();
    }

    fn insert_fixup(&mut self, z: &mut RedBlackNode<'a, T>) {
        if z.parent.is_none() {
            return;
        }

        while z.parent.unwrap().colour {
            if z.parent.unwrap().parent.is_some()
                && *z.parent.unwrap()
                    == *z.parent.unwrap().parent.unwrap().left.unwrap()
            {
                let y = z.parent.unwrap().parent.unwrap().right.unwrap();

                if y.colour {
                    z.parent.unwrap().colour = false;
                    y.colour = false;
                    z.parent.unwrap().parent.unwrap().colour = true;
                    z = z.parent.unwrap().parent.unwrap();
                } else {
                    if z.parent.unwrap().right.is_some()
                        && *z == *z.parent.unwrap().right.unwrap()
                    {
                        z = z.parent.unwrap();
                        self.left_rotate(z);
                    }

                    z.parent.unwrap().colour = false;
                    z.parent.unwrap().parent.unwrap().colour = true;
                    self.right_rotate(z.parent.unwrap().parent.unwrap());
                }
            } else {
                if z.parent.unwrap().parent.is_some()
                    && *z.parent.unwrap()
                        == *z.parent.unwrap().parent.unwrap().right.unwrap()
                {
                    let y = z.parent.unwrap().parent.unwrap().left.unwrap();

                    if y.colour {
                        z.parent.unwrap().colour = false;
                        y.colour = false;
                        z.parent.unwrap().parent.unwrap().colour = true;
                        z = z.parent.unwrap().parent.unwrap();
                    } else {
                        if z.parent.unwrap().left.is_some()
                            && *z == *z.parent.unwrap().left.unwrap()
                        {
                            z = z.parent.unwrap();
                            self.right_rotate(z);
                        }

                        z.parent.unwrap().colour = false;
                        z.parent.unwrap().parent.unwrap().colour = true;
                        self.left_rotate(z.parent.unwrap().parent.unwrap());
                    }
                }
            }
        }

        self.root.unwrap().colour = false;
    }
}

fn print_node<T>(node: &RedBlackNode<T>)
where
    T: Display,
{
    match &node.left {
        Some(l) => print_node(l),
        None => {}
    };

    println!("{}", node.elem);

    match &node.right {
        Some(r) => print_node(r),
        None => {}
    };
}

pub fn print_tree<T>(tree: &RedBlackTree<T>)
where
    T: Display,
{
    match &tree.root {
        Some(root) => print_node(&root),
        None => {}
    };
}

fn main() {
    let my_tree: RedBlackTree<u64> = RedBlackTree::new();
    print_tree(&my_tree);
}

However, the compiler complains due to the conflicting lifetime on line 43, with:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:43:68
   |
43 |         let mut x: Option<&'a mut RedBlackNode<'a, T>> = self.root.as_mut();
   |                                                                    ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 39:5...
  --> src/main.rs:39:5
   |
39 | /     pub fn add(&mut self, elem: T) {
40 | |         let z: RedBlackNode<'a, T> = RedBlackNode::new(elem);
41 | |
42 | |         let mut y: Option<&'a mut RedBlackNode<'a, T>> = None;
...  |
69 | |         self.insert_fixup(&mut z);
70 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:43:58
   |
43 |         let mut x: Option<&'a mut RedBlackNode<'a, T>> = self.root.as_mut();
   |                                                          ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 34:6...
  --> src/main.rs:34:6
   |
34 | impl<'a, T: PartialOrd> RedBlackTree<'a, T> {
   |      ^^
note: ...so that the expression is assignable
  --> src/main.rs:43:58
   |
43 |         let mut x: Option<&'a mut RedBlackNode<'a, T>> = self.root.as_mut();
   |                                                          ^^^^^^^^^^^^^^^^^^
   = note: expected `std::option::Option<&'a mut RedBlackNode<'a, T>>`
              found `std::option::Option<&mut RedBlackNode<'a, T>>`

I'm assuming this is due to the definition of RedBlackTree<'a, T> taking ownership of the root node inside the Option type (i.e., on line 31).

How can this be fixed without breaking the interface to RedBlackTree?

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
jmcph4
  • 197
  • 2
  • 8
  • 1
    Do yourself a favor: read [Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/) before trying to write any recursively defined data structure in Rust. You can do it, but generally speaking you're either going to leave performance on the table (like you might in a managed language such as Java) or use a lot of `unsafe` (as you would in C, since everything is unsafe there). – trent Sep 27 '20 at 01:59
  • Does this answer your question? [How do I express mutually recursive data structures in safe Rust?](https://stackoverflow.com/questions/36167160/how-do-i-express-mutually-recursive-data-structures-in-safe-rust) – trent Sep 27 '20 at 02:06

0 Answers0