I have a function that needs to operate on two parts of a single array.
The purpose is to be able to build an #[nostd] allocator that can return a variable slice of a bigger array to the caller and hang on to the remainder of the array for future allocations.
Here's example code that fails:
fn split<'a>(mut item: &'a mut [i32], place: usize) -> (&'a mut [i32], &'a mut [i32]) {
(&mut item[0..place], &mut item[place..])
}
fn main() {
let mut mem: [i32; 2048] = [1; 2048];
let (mut array0, mut array1) = split(&mut mem[..], 768);
array0[0] = 4;
println!("{:?} {:?}", array0[0], array1[0]);
}
the error is as follows:
error[E0499]: cannot borrow `*item` as mutable more than once at a time
--> src/main.rs:2:32
|
2 | (&mut item[0..place], &mut item[place..])
| ---- ^^^^ second mutable borrow occurs here
| |
| first mutable borrow occurs here
3 | }
| - first borrow ends here
This pattern also can be helpful for in-place quicksort, etc.
Is there anything unsafe about having two mutable references to nonoverlapping slices of the same array? If there's no way in pure Rust, is there a "safe" unsafe incantation that will allow it to proceed?
Is there anything unsafe about having two mutable references to nonoverlapping slices of the same array?
There isn't, but Rust's type system cannot currently detect that you're taking mutable references to two non-overlapping parts of a slice. As this is a common use case, Rust provides a safe function to do exactly what you want: std::slice::split_at_mut.
fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T])
Divides one &mut into two at an index.
The first will contain all indices from [0, mid) (excluding the index
mid itself) and the second will contain all indices from [mid, len)
(excluding the index len itself).
The final code is:
fn main() {
let mut mem : [i32; 2048] = [1; 2048];
let (mut array0, mut array1) = mem[..].split_at_mut(768);
array0[0] = 4;
println!("{:?} {:?}", array0[0], array1[0]);
}
Wow that was such a perfect match. Thanks for finding this!
Related
This question already has an answer here:
What is lifetime elision in very simple terms?
(1 answer)
Closed 3 months ago.
I have this function that borrows two individual elements from a vector. It works as expected:
fn borrow_mut_two<T>(v: &mut [T], i: usize, j: usize) -> (&mut T, &mut T) {
assert!(i < j);
let (left, right) = v.split_at_mut(j);
(&mut left[i], &mut right[0])
}
fn test() {
let mut v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
let i = 2;
let j = 5;
let (ref_a, ref_b) = borrow_mut_two(&mut v, i, j);
*ref_a += 1;
*ref_b += 5;
assert_eq!(*ref_a, i + 1);
assert_eq!(*ref_b, j + 5);
}
What I'm trying to understand is why the following code doesn't compile:
fn test() {
let mut v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
let i = 2;
let j = 5;
let (ref_a, ref_b) = borrow_mut_two(&mut v, i, j);
// Added this line:
let (other_ref_a, other_ref_b) = borrow_mut_two(&mut v, i, j);
*ref_a += 1;
*ref_b += 5;
assert_eq!(*ref_a, i + 1);
assert_eq!(*ref_b, j + 5);
}
It seems it works in a safe manner, because it doesn't allow me to mutably borrow the same elements twice (or potentially other elements).
My question is how does the compiler know that this is unsafe (and therefore reject compiling it)?
The compiler errors are:
229 | let (ref_a, ref_b) = borrow_mut_two(&mut v, i, j);
| ------ first mutable borrow occurs here
230 | let (other_ref_a, other_ref_b) = borrow_mut_two(&mut v, i, j);
| ^^^^^^ second mutable borrow occurs here
As far as I know the return value of borrow_mut_two is the tuple (&mut T, &mut T), which may or may not be a borrow to self, but it seems the compiler does know it's borrowing self. My assumptions may be wrong though 🙂.
The only thing that comes to mind is that Rust automatically adds the lifetime:
fn borrow_mut_two<'a, T>(v: &'a mut [T], i: usize, j: usize) -> (&'a mut T, &'a mut T)
Which would mean that in my test function, 'a is still alive (i.e. self mutably borrowed) due to the first call to borrow_mut_two while the second call happens, and that's how it detects a second mutable borrow.
But I'd like to confirm if this is correct.
Extra
It could be related to this part of the book. The only difference I see is that my function returns a tuple. So the question can be reduced to: Does Rust's second lifetime elision rule also add 'a to each element of a tuple? If so, then my doubt is solved:
The first rule is that the compiler assigns a lifetime parameter to
each parameter that’s a reference. In other words, a function with one
parameter gets one lifetime parameter: fn foo<'a>(x: &'a i32); a
function with two parameters gets two separate lifetime parameters: fn
foo<'a, 'b>(x: &'a i32, y: &'b i32); and so on.
The second rule is that, if there is exactly one input lifetime
parameter, that lifetime is assigned to all output lifetime
parameters: fn foo<'a>(x: &'a i32) -> &'a i32.
Yes, your understanding is correct - due to lifetime elision, the following two function signatures are equivalent:
fn borrow_mut_two<T>(v: &mut [T], i: usize, j: usize) -> (&mut T, &mut T)
fn borrow_mut_two<'a, T>(v: &'a mut [T], i: usize, j: usize) -> (&'a mut T, &'a mut T)
Because the lifetimes of the output are tied to the lifetime of v, the compiler knows that v is still mutably borrowed until those derived references stop being used.
The issue in your second code is that you are trying to borrow mutably v while an other mutable borrow is still alive, just as the compiler indicates to you. To be more precise, the compiler sees the following constraints:
fn test() {
// ...
let (ref_a, ref_b) = borrow_mut_two(&'3 mut v, i, j); // ------+
// ^^^^^ ^^^^^ ^^^^^^^ Let's call // |
// +---+ this lifetime '3 // |
// | // |
// Let's call the lifetime of these mutable borrows '1 // |
// Added this line: // +- '1
let (other_ref_a, other_ref_b) = borrow_mut_two(&'4 mut v, i, j); // -+ '2 |
// ^^^^^^^^^^^ ^^^^^^^^^^^ // | |
// +------+ Let's call the lifetimes of these borrows '2 // -+ |
*ref_a += 1; // |
*ref_b += 5; // ------+
}
First of all, '3 and '4 cannot outlive the lifetime of v, but this isn't very important in this case so we can forget about it. Then, due to the signature of borrow_mut_two, '1='3 and '2='4. Furthermore, since we are talking about mutable borrows, there can be at most one at a time. Finally, I have indicated the minimum span of '1 and '2.
When the compiler tries to enforce all these constraints, it will fail, because clearly '1 and '2 cannot be disjoint while living at least for as much time as they are useful.
In fact, it is sometimes possible to make this kind of layout work, because '1 is never used when '2 is used, and '2's span is included in '1's. In these cases, the compiler says the borrows are stacked, and it could accept them if '2 was a reborrow of '1. It is logically the case, but split_at_mut prevents the compiler from understanding this because internally it uses unsafe code on which the compiler can't reason as easily as it would otherwise.
I have a function that needs to operate on two parts of a single array.
The purpose is to be able to build an #[nostd] allocator that can return a variable slice of a bigger array to the caller and hang on to the remainder of the array for future allocations.
Here's example code that fails:
fn split<'a>(mut item: &'a mut [i32], place: usize) -> (&'a mut [i32], &'a mut [i32]) {
(&mut item[0..place], &mut item[place..])
}
fn main() {
let mut mem: [i32; 2048] = [1; 2048];
let (mut array0, mut array1) = split(&mut mem[..], 768);
array0[0] = 4;
println!("{:?} {:?}", array0[0], array1[0]);
}
the error is as follows:
error[E0499]: cannot borrow `*item` as mutable more than once at a time
--> src/main.rs:2:32
|
2 | (&mut item[0..place], &mut item[place..])
| ---- ^^^^ second mutable borrow occurs here
| |
| first mutable borrow occurs here
3 | }
| - first borrow ends here
This pattern also can be helpful for in-place quicksort, etc.
Is there anything unsafe about having two mutable references to nonoverlapping slices of the same array? If there's no way in pure Rust, is there a "safe" unsafe incantation that will allow it to proceed?
Is there anything unsafe about having two mutable references to nonoverlapping slices of the same array?
There isn't, but Rust's type system cannot currently detect that you're taking mutable references to two non-overlapping parts of a slice. As this is a common use case, Rust provides a safe function to do exactly what you want: std::slice::split_at_mut.
fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T])
Divides one &mut into two at an index.
The first will contain all indices from [0, mid) (excluding the index
mid itself) and the second will contain all indices from [mid, len)
(excluding the index len itself).
The final code is:
fn main() {
let mut mem : [i32; 2048] = [1; 2048];
let (mut array0, mut array1) = mem[..].split_at_mut(768);
array0[0] = 4;
println!("{:?} {:?}", array0[0], array1[0]);
}
Wow that was such a perfect match. Thanks for finding this!
If I have a local, mutable vector, I can partition it as follows, copied from the documentation of partition.
let mut a = vec![1, 2, 3, 4];
let (even, odd): (Vec<i32>, Vec<i32>) = a.into_iter().partition(|&n| n % 2 == 0);
The a vector is consumed (moved) in this process. However, the same call to partition doesn't work if I have a borrowed mutable reference. If I try to use the same code in that case, I get the error:
error[E0277]: the trait bound `std::vec::Vec<i32>: std::iter::Extend<&mut i32>` is not satisfied
--> src/main.rs:2:59
|
2 | let (even, odd): (Vec<i32>, Vec<i32>) = a.into_iter().partition(|n| **n % 2 == 0);
| ^^^^^^^^^ the trait `std::iter::Extend<&mut i32>` is not implemented for `std::vec::Vec<i32>`
|
= help: the following implementations were found:
<std::vec::Vec<T> as std::iter::Extend<&'a T>>
<std::vec::Vec<T> as std::iter::Extend<T>>
Based on How to make a Rust mutable reference immutable?, I wrote the following, which compiles and puts the right values into even and odd.
fn doit(a: &mut Vec<i32>) {
let (even, odd): (Vec<i32>, Vec<i32>) = (&*a).into_iter().partition(|&n| n % 2 == 0);
println!("even {:?}, odd {:?}, a {:?}", even, odd, a);
}
However, this does not consume the original vector, even though I'm using into_iter(). There's something about mutability, borrowing, or iterators that I'm just not getting here.
As others have implied, you can't move the original vector since you don't own it. However you can move all the values out of the vector, leaving it empty. This can be accomplished with the drain method:
fn doit(a: &mut Vec<i32>) {
let (even, odd): (Vec<i32>, Vec<i32>) = a.drain(..).partition(|&n| n % 2 == 0);
println!("even {:?}, odd {:?}, a {:?}", even, odd, a);
}
playground
The reason is that the IntoIterator trait is implemented differently for &'a mut Vec<T> and &'a Vec<T> then it is for Vec<T>. The First two create an iterator by value where as the Vec<T> version creates a consuming iterator, that is, one that moves each value out of the vector (from start to end). The vector cannot be used after calling into_iter(). So you can think of the first two &'a mut Vec<T> and &'a Vec<T> as using the values inside the reference to the Vector to create an iterator. Where as the Vec<T> you can think of it removing the values out of the Vec<T> and putting them into the iterator. Shepmaster's comment of not being able to consume something that you don't own is the reason why they are implemented differently.
Also be aware that there is different ways to get an iterator.
From the Rust documentation:
iter(), which iterates over &T.
iter_mut(), which iterates over &mut T.
into_iter(), which iterates over T.
So you could also keep the function the same without doing (&*a) by using iter() instead of into_iter().
fn doit(a: &mut Vec<i32>) {
let (even, odd): (Vec<i32>, Vec<i32>) = a.iter().partition(|&n| n % 2 == 0);
println!("even {:?}, odd {:?}, a {:?}", even, odd, a);
}
In section 3.2 of the Nomicon, under the heading "liveness", it says
However it's often the case that Rust isn't sufficiently smart to
prove that multiple borrows are disjoint.
What is an example where the Rust compiler cannot prove that they are disjoint? Will this ever occur in a tuple struct?
The key is in the previous sentence:
Rust explicitly enables [reborrowing into multiple mutable references] to be done with disjoint struct fields, because disjointness can be statically proven
Outside of this case, the compiler cannot tell that two borrows are disjoint. In practice, this means that the compiler cannot tell that borrows resulting from a function call will be disjoint.
struct Thing {
a: i32,
b: i32,
}
fn example_works(thing: &mut Thing) {
let a = &mut thing.a;
let b = &mut thing.b;
}
fn get_a(thing: &mut Thing) -> &mut i32 {
&mut thing.a
}
fn get_b(thing: &mut Thing) -> &mut i32 {
&mut thing.b
}
fn example_doesnt_work(thing: &mut Thing) {
let a = get_a(thing);
let b = get_b(thing);
println!("{}, {}", a, b);
}
error[E0499]: cannot borrow `*thing` as mutable more than once at a time
--> src/lib.rs:26:19
|
25 | let a = get_a(thing);
| ----- first mutable borrow occurs here
26 | let b = get_b(thing); // cannot borrow `*thing` as mutable more than once at a time
| ^^^^^ second mutable borrow occurs here
27 | println!("{}, {}", a, b);
| - first borrow later used here
Will this ever occur in a tuple struct?
Not specifically because it's a tuple struct, but yes, it can happen for the same reasons. If you obtain a borrow from a function call, you will get the same problem as a "traditional" struct.
In Go, copying slices is standard-fare and looks like this:
# It will figure out the details to match slice sizes
dst = copy(dst[n:], src[:m])
In Rust, I couldn't find a similar method as replacement. Something I came up with looks like this:
fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize {
let mut c = 0;
for (&mut d, &s) in dst.iter_mut().zip(src.iter()) {
d = s;
c += 1;
}
c
}
Unfortunately, I get this compile-error that I am unable to solve:
error[E0384]: re-assignment of immutable variable `d`
--> src/main.rs:4:9
|
3 | for (&mut d, &s) in dst.iter_mut().zip(src.iter()) {
| - first assignment to `d`
4 | d = s;
| ^^^^^ re-assignment of immutable variable
How can I set d? Is there a better way to copy a slice?
Yes, use the method clone_from_slice(), it is generic over any element type that implements Clone.
fn main() {
let mut x = vec![0; 8];
let y = [1, 2, 3];
x[..3].clone_from_slice(&y);
println!("{:?}", x);
// Output:
// [1, 2, 3, 0, 0, 0, 0, 0]
}
The destination x is either a &mut [T] slice, or anything that derefs to that, like a mutable Vec<T> vector. You need to slice the destination and source so that their lengths match.
As of Rust 1.9, you can also use copy_from_slice(). This works the same way but uses the Copy trait instead of Clone, and is a direct wrapper of memcpy. The compiler can optimize clone_from_slice to be equivalent to copy_from_slice when applicable, but it can still be useful.
This code works, even though I am not sure if it the best way to do it.
fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize {
let mut c = 0;
for (d, s) in dst.iter_mut().zip(src.iter()) {
*d = *s;
c += 1;
}
c
}
Apparently not specifying access permissions explicitly did the trick. However, I am still confused about this and my mental model doesn't yet cover what's truly going on there.
My solutions are mostly trial and error when it comes to these things, and I'd rather like to truly understand instead.
Another variant would be
fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize {
dst.iter_mut().zip(src).map(|(x, y)| *x = *y).count()
}
Note that you have to use count in this case, since len would use the ExactSizeIterator shortcut and thus never call next, resulting in a no-op.