Nick
Nick

Reputation: 10499

Multiple borrow in previous iteration of loop

Following is the code I'm working on, I explore a directory path with a queue and I want to store the filesystem tree in my data structure (the enum Entry):

use failure::Error;
use std::collections::VecDeque;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn main() -> Result<(), Error> {
    let paths = visit_dir(Path::new(".")).map_err(Error::from)?;
    Ok(())
}

#[derive(Debug)]
enum Entry {
    Dir(PathBuf, Vec<Entry>),
    File(PathBuf),
}

impl Entry {
    fn new_dir(path: &Path) -> Entry {
        Entry::Dir(path.to_path_buf(), Vec::new())
    }

    fn new_file(path: &Path) -> Entry {
        Entry::File(path.to_path_buf())
    }

    /// Append a new Entry to self if self is a directory.
    fn push(&mut self, path: &Path) -> Option<&mut Entry> {
        if let Entry::Dir(_, ref mut content) = self {
            let entry = if path.is_dir() {
                Entry::new_dir(path)
            } else {
                Entry::new_file(path)
            };
            content.push(entry);
            return content.last_mut();
        }
        None
    }

    fn path(&self) -> &Path {
        match self {
            Entry::Dir(path, _) => path,
            Entry::File(path) => path,
        }
    }
}

fn visit_dir(root: &Path) -> io::Result<Entry> {
    let mut dir = Entry::new_dir(root);
    let mut queue = VecDeque::new();
    queue.push_back(&mut dir);

    while !queue.is_empty() {
        let parent = queue.pop_front().unwrap();
        let path = parent.path();
        if path.is_dir() {
            for entry in fs::read_dir(path)? {
                let entry = entry?;
                let path = entry.path();
                let entry = parent.push(&path).unwrap();

                if path.is_dir() {
                    queue.push_back(entry);
                }
            }
        }
    }

    Ok(dir)
}

Link to Playground

The error I am getting is:

error[E0499]: cannot borrow `*parent` as mutable more than once at a time
  --> src/main.rs:61:29
   |
61 |                 let entry = parent.push(&path).unwrap();
   |                             ^^^^^^ mutable borrow starts here in previous iteration of loop

My questions are:

Upvotes: 3

Views: 676

Answers (1)

Boiethios
Boiethios

Reputation: 42759

  • entry borrows parent mutably in the line:

    let entry = parent.push(&path).unwrap();
    
  • Then, you do not release entry, because you store it in queue. So, parent is still borrowed mutably when this is the 2nd iteration in the loop. This is unsafe to do that.

What you are trying to do is a tree of mutable references. That won't work in Rust, and this is generally a bad idea. You should modify the way you want to implement that.

Upvotes: 2

Related Questions