0

I am trying (and struggling) to create a simple tree structure in Rust and a breadth-first iterator for it, however I've been stuck for hours trying to fix lifetimes. This is the closest I've got to a successful build, but the only error is the one in the title.

Here is the full code:

use std::{vec, vec::Vec};

pub struct Tree<K, V>
where K: PartialEq + Clone {
    subtrees: Vec<Tree<K, V>>,
    key: K,
    value: Option<V>,
}

impl<K, V> Tree<K, V>
where K: PartialEq + Clone {
    pub const fn new(root_key: K, root_value: Option<V>) -> Tree<K, V> {
        Tree {
            subtrees: Vec::new(),
            key: root_key,
            value: root_value,
        }
    }

    pub fn get_subtree(&mut self, key: K) -> Option<&mut Self> {
        for tree in &mut self.subtrees {
            if tree.key == key {
                return Some(tree);
            }
        }
        None
    }

    pub fn value(&mut self) -> Option<&mut V> {
        self.value.as_mut()
    }

    pub fn insert_subtree(&mut self, key: K, value: Option<V>) {
        self.subtrees.push(Tree::new(key, value));
    }

    pub fn iter_bfs(&mut self) -> BFSIterator<K, V> {
        BFSIterator {
            levels: vec![(0, vec![SearchState {
                tree: self,
                parent: None,
                visited: false,
            }])],
        }
    }
}

struct SearchState<'a, K: 'a, V: 'a>
where K: PartialEq + Clone {
    tree: &'a mut Tree<K, V>,
    parent: Option<&'a mut Tree<K, V>>,
    visited: bool,
}

struct BFSIterator<'a, K: 'a, V: 'a>
where K: PartialEq + Clone {
    levels: Vec<(usize, Vec<SearchState<'a, K, V>>)>,
}

impl<'a, K, V> BFSIterator<'a, K, V>
where K: PartialEq + Clone {
    fn current_level(&mut self) -> &mut (usize, Vec<SearchState<'a, K, V>>) {
        self.levels.last_mut().unwrap()
    }

    fn current_node(&mut self) -> &mut SearchState<'a, K, V> {
        let index = self.current_level().0;
        &mut self.current_level().1[index]
    }

    fn advance_vertical(&mut self) {
        // current node is parent
        let parent = &self.current_node().tree;
        // fill next level vec with children of current node
        let mut level_vec = Vec::new();
        let a_tree = self.current_node().tree;
        for tree in &mut a_tree.subtrees {
            level_vec.push(SearchState {
                tree,
                parent: Some(*parent),
                visited: false,
            });
        }
        // advance horizontally to get to the next one when we go back here
        self.current_level().0 += 1;
        // if it is a leaf, do not advance
        if level_vec.len() != 0 {
            self.levels.push((0, level_vec));
        }
    }
}

impl<'a, K: 'a, V: 'a> Iterator for BFSIterator<'a, K, V>
where K: PartialEq + Clone {
    type Item = &'a mut Tree<K, V>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current_node().visited {
            if self.current_level().0 < self.current_level().1.len() {
                // we can go down if not at the end of the line
                self.advance_vertical();
                let junk_state = self.current_node().tree;
                return Some(junk_state);
            } else {
                if self.levels.len() > 0 {
                    // if everything on this line has been searched, go back
                    self.levels.pop();
                } else {
                    // got back to beginning, quit
                    return None;
                }
            }
        } else {
            let ret_ref = self.current_node().tree;
            self.current_node().visited = true;
            if self.current_level().0 < self.current_level().1.len() - 1 {
                // advance horizontally if we can
                self.current_level().0 += 1;
            } else {
                // last node visited on this level, let's advance horizontally from the beginning if we can
                // go back to node 0 horizontally
                self.current_level().0 = 0;
                self.advance_vertical();
                return Some(ret_ref);
            }

        }
        None
    }
}

The problematic line is the following:

// current node is parent
        let parent = &self.current_node().tree;

Here, it is apparent that the field tree of the struct SearchState is a mutable reference with lifetime 'a, but Rust struggles to realize, as shown in the full error message:

cannot infer an appropriate lifetime for autoref due to conflicting requirements
expected `Vec<SearchState<'a, _, _>>`
   found `Vec<SearchState<'_, _, _>>`

What are your suggestions to fix it? I really don't want to end up just using raw pointers instead of references.

lorinet3
  • 444
  • 4
  • 11
  • 2
    From a quick look, it appears that constructing a `SearchState` will be impossible, as you can't hold a mutable reference to the parent tree and the child tree at the same time, because the parent tree owns the child tree. – PitaJ Dec 22 '22 at 17:33
  • You may be able to store the parent and the child key instead. – Chayim Friedman Dec 22 '22 at 17:38
  • 1
    I've implemented a [Playground with a mutable iterator over key-value pairs](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7eeb7517accaf33de0f9ae071b111393) using two accumulators. – PitaJ Dec 22 '22 at 18:09
  • 1
    @PitaJ Thank you, I didn't know about this algorithm at all! Works flawlessly. – lorinet3 Dec 22 '22 at 21:22

0 Answers0