RefMut not dropped at the end of match

I'm having trouble with the following error:

thread 'main' panicked at 'already mutably borrowed: BorrowError'

I tracked down the error using the backtrace to the following code:

let object_node_ref =
    find_node_or_create(&graph_ref, &object_iri);

let mut graph = graph_ref.borrow_mut();
graph.add_edge(&subject_node_ref, &object_node_ref)

And it seems that my error is inside the find_node_or_create() function, wich is:

fn find_node_or_create<'a>(graph_ref: &'a GraphRef, iri: &str) -> NodeRef {
    let maybe_node = {
        let graph = graph_ref.borrow();
        let mut traverser = graph.traverser();
        let option_tuple = traverser
            .nodes()
            .find_with_label(iri)
            .as_nodes_iter()
            .next();

        option_tuple.map(|(_, node)| node.clone())
     };

    match maybe_node {
        Some(node) => node,
        None => {
            let mut graph = graph_ref.borrow_mut();
            let node_ref = graph.add_node();
            node_ref
                .borrow_mut()
                .insert_label(iri);
            node_ref.clone()
        }
   }
}

And I know that the error lies at the end of this function, here:

node_ref
    .borrow_mut()
    .insert_label(iri);
node_ref.clone()

Because when I remove the .borrow_mut().insert_label(iri); part the code run perfectly. My guessing is that for some reason the RefMut created bY THIS specific borrow_mut() is not dropped automatically. But I don't understand why.

Thanks for the help.

Variables in Rust are semantically meaningful. Assigning something to a variable extends its lifetime until the end of the scope.

borrow_mut().do_something() does a different thing than let tmp = borrow_mut(); tmp.do_something().

If you want borrows to end earlier than implicit cleanup at the end of scope, add explicit drop, e.g. drop(graph);

The string "already mutably borrowed" seems to come from the RefCell::borrow function when clone is called. Does putting the borrow_mut into a block help ?

{
    node_ref
        .borrow_mut()
        .insert_label(iri);
}
node_ref.clone()

@kornel I tried the following without luck:

let mut node = node_ref.borrow_mut();
node.insert_label(iri);
drop(node);

@tobi34 from my tests the error orriginate because of the .borrow_mut() doesn't seems to drop the RefMut created. While it should simply borrow the Rc<RefCell> as a RefMut and drop it at the end of the function. Nevertheless I tried the following:

{
    node_ref
        .borrow_mut()
        .insert_label(iri);
}
node_ref.clone()

And still face the same issue...
All the code of the project is available on my github:
https://github.com/loustak/rugdb/blob/refactoring/src/main.rs

You should drop(graph) rather than drop(node). graph is the RefMut that's causing the problem, not node_ref.

Alternatively, you can get rid of graph altogether:

None => {
    let node_ref = graph_ref.borrow_mut().add_node();
    // ...
}
2 Likes

This was going to be my advise. Never create a variable to hold a guard (like borrow_mut() creates) unless your actual goal is to hold onto the guard until the end of the block.

1 Like

Thanks a lot, droping the graph solved the problem. I also add a more subtle bug releated when creating an edge between two nodes when the two nodes where the same.
This is solved.

Thanks to everyone.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.