Tricky case of "cannot borrow ... as mutable more than once at a time"

Hi all.

There are many help requests about this error message but I wasn't able to find something similar to my use case. This is a simplified example of my actual code:

fn main() {	
	let mut v = vec![vec![5; 4], vec![6; 4], vec![7; 4]];

	let a = v[0].as_mut_slice();
	let b = v[1].as_mut_slice();
	b.clone_from_slice(a);

	println!("{v:#?}");
}

Obviously this doesn't work - the compiler cannot infer that I'm taking a mutable reference to two distinct inner vectors so it conservatively goes for the whole outer v vector twice (please correct me if I'm wrong here).

Also, if it matters, I'm missing the immutable reference .as_slice() method; the inner vectors in the example above are in reality Jack's output audio buffers (Port in jack - Rust) that expose only the .as_mut_slice() method.

I know I can work around this problem with an intermediate temporary buffer: copy from a to temp, drop the mutable reference to a, copy temp to b. But for performance reasons, I'd like to avoid this extra copy pass.

Is there a way to make this direct copy? If not, can the unsafe black magic help me and how?

Thanks

let [ref mut a, ref mut b, ..] = *v else { panic!("fewer than two elements") };
let (a, b) = (a.as_mut_slice(), b.as_mut_slice());
b.clone_from_slice(a);

Wow... that was a very fast answer! Undoubtedly it solves my example.

But I cannot drop the indexes because the inner vectors involved in the copy are known only at run time, I over-simplified the example:

fn main() {

	let src_index = 0; // determined at runtime
	let dst_index = 1; // determined at runtime

	let mut v = vec![vec![5; 4], vec![6; 4], vec![7; 4]];

	let a = v[src_index].as_mut_slice();
	let b = v[dst_index].as_mut_slice();
	b.clone_from_slice(a);

	println!("{v:#?}");
}

Still good to learn it is possible to unpack a vector that way. TIL
Thanks.

In the case of (a fixed number of) dynamically-determined distinct indices, you'd ideally reach for <[_]>::get_many_mut, but that's unstable. You can still solve the problem without writing unsafe code, though -- here's one way:

fn get_two_mut<T>(xs: &mut [T], i: usize, j: usize) -> (&mut T, &mut T) {
    assert_ne!(i, j);
    if j < i { return get_two_mut(xs, j, i) }
    let [ref mut ith, ref mut rest @ ..] = xs[i..] else { panic!() };
    // or: let (ith, rest) = xs[i..].split_first_mut().unwrap();
    let jth = &mut rest[j - i - 1];
    (ith, jth)
}

<[_]>::split_at_mut is also handy for this kind of thing.

You're essentially building an array of the mutable references to all the inner vectors (or, at least, a relevant portion) and then pick only two of them. Pretty smart!

This is an arrow to keep in my rusty quiver. Thanks a lot!

1 Like

Oh, this way is nicer:

incorrect code hidden
fn get_two_mut<T>(xs: &mut [T], i: usize, j: usize) -> (&mut T, &mut T) {
    assert_ne!(i, j);
    if j < i { return get_two_mut(xs, j, i) }
    let [ref mut ith, .., ref mut jth] = xs[i..=j] else { unreachable!() };
    (ith, jth)
}

The jargon here is "slice patterns".

Edit: That code has a bug, ith and jth will be returned in the wrong order if j < i! Corrected version:

fn get_two_mut<T>(xs: &mut [T], i: usize, j: usize) -> (&mut T, &mut T) {
    assert_ne!(i, j);
    if j < i {
        let (jth, ith) = get_two_mut(xs, j, i);
        return (ith, jth);
    }
    let [ref mut ith, .., ref mut jth] = xs[i..=j] else { unreachable!() };
    (ith, jth)
}
6 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.