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?
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)
}
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!