Search code examples
rustborrow-checkerborrowingborrowmutable-reference

Rust linked list cannot borrow previous and next elemt as mutable (just need immutable reference)


Currently, I'm working on a little application to simulate (multiple chained) pendulums. To save them I decided to go for a std::collections::LinkedList.

Displaying them and moving them statically is not a problem, but for calculating the real movement I need to know some values of the parent and the child pendulum.

I don't really need a mutable reference to them, but the linked list API doesn't let me take an immutable one. But I guess this would not change the compiler's mind anyway since it's still a mutable and some immutable borrows.

My code looks like this:

let mut cursor = /* some linked list with 0 or more elements */.cursor_front_mut();

// the first element gets a phantom parent, that has no effect on the calculation
let mut first = Pendulum::zero_center();
// same with the last element. But we don't know the position of this phantom yet.
let mut last;

while let Some(current) = cursor.current() { // << first mutable borrow occurs here
    { 
        // new scope, so I don't mutate the cursor while holding mutable references
        // to the surrounding elements
        // (I don't really need the next two borrows to be mutable)

        let parent = match cursor.peek_prev() { // << second mutable borrow occurs here
            Some(parent) => parent,
            None => &mut first
        };
        let child = match cursor.peek_next() { // third mutable borrow occurs here
            Some(child) => child,
            None => {
                last = Pendulum::zero(current.bottom_pos); // << bottom_pos is of type Copy
                &mut last
            }
        };

        // update the current pendulum
        // update does take a immutable reference of parent and child
        // since it only needs to read some values of them
        current.update(parent, child);
    }
    cursor.move_next();
}

If I wrap this code in unsafe {}, the compiler doesn't care and keeps telling me that I have multiple mutable borrows + an unnecessary unsafe block.

It would be awsome if someone could help me!
If using a LinkedList is total rubbish here and there's a better way to do it please let me know!

Many thanks in advance!


Solution

  • Generally, mutable references require exclusive access to the thing they point to, and unsafe blocks have no influence on this. Raw pointers do not have this requirement, so writing code that violates these requirements would have to use raw pointers.

    Implementing a linked list with unsafe Rust would be outside the scope of an SO answer, but I recommend Learning Rust with too many Linked Lists as a resource on ways to approach this.

    Sometimes building a linked list using indexes into a vector is a good alternate approach, which side steps any issues on the many requirements Rust puts on its references.