How is `get_disjoint_mut` supposed to be used even?

I'm trying to clone_from one element of a vector to another (without any temporary copy in between):

#[derive(Clone)]
struct MyBigStruct { ... }

fn myfunc(data: Vec<MyBigStruct>, from: usize, to: usize) {
    let indices = states
        .get_disjoint_mut([to as usize, from as usize])
        .expect("Failed to get disjoint indices");
    indices[0].clone_from(indices[1]);
    // ... rest of the function logic
}

However, this fails:

error[E0502]: cannot borrow `*indices[_]` as mutable because it is also borrowed as immutable
   --> src/main.rs:154:33
    |
154 | ...                   indices[0].clone_from(indices[1]);
    |                       ^^^^^^^^^^^----------^----------^
    |                       |          |          |
    |                       |          |          immutable borrow occurs here
    |                       |          immutable borrow later used by call
    |                       mutable borrow occurs here

For more information about this error, try `rustc --explain E0502`.

I also can't move out of the references from the indices array, as &mut isn't copy:

let from_state = indices[0];
let to_state = indices[1];
   --> src/main.rs:154:50
    |
154 | ...                   let from_state = indices[0];
    |                                        ^^^^^^^^^^
    |                                        |
    |                                        cannot move out of here
    |                                        move occurs because `indices[_]` has type `&mut StatemapInputDatum<CpuState>`, which does not implement the `Copy` trait
    |
help: consider borrowing here
    |
154 |                                 let from_state = &indices[0];
    |                                                  +

(Borrowing does not work, that just creates a &&mut, which is no help here. And this is performance critical code, I need to keep the number of indirections to a minimum.)

It seems to me that get_disjoint_mut is entirely useless if you can't actually work with multiple of the entries at once. I could use split_at_mut but then I need to figure out which index is larger and deal with computing offsets like that.

What is the best way to do this given that this that creates the ideal assembly (bounds check for from & to, check that they are different, then a simple clone)?

1 Like

You can destruct the returned array

let [a, b] = indices;

3 Likes

Oh, duh. Didn't realise Rust had destructuring for arrays, thought it was only for tuples.

1 Like

Note that derive(Clone) doesn't override clone_from(), so you will see no perf benefit over using indices[0] = indices[1].clone().

Slice/array destructuring is very powerful because you can do things like [first, rest @ ..] or even [first, mid @ .., last]. And slices you can of course match against patterns of different lengths if you want to elegantly handle cases like 0, 1, infinite.

3 Likes

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.