Weird borrowck issues with &mut &mut [u8]


#1

Hi to all. The background for problem: I ran into some bizarre borrowck issues when trying to write a function that would modify a &mut &mut [u8]. The goal here was to make it simple to shove data http://www.kynix.com/Search/data.html into a [u8, …512] by virtue of copying data into the corresponding &mut [u8] and then modifying the slice. I tried three different approaches, and they all had issues. The various errors are commented into the source.

(All 3 approaches require use std::vdc::MutableCloneableVector)

The first approach tried to define a function append(buf: &mut &mut [u8], v: &[u8]) that would copy the data into buf and then modify *buf to contain the new slice. This ran into an odd lifetime error where it thinks that I can’t say *buf = buf.mut_slice_from(len). It claims the lifetime of buf is too short, but I don’t see why that matters. I’m actually re-slicing *buf, and putting the result back into the same location that held the original slice, so I would expect it to have the same lifetime and, therefore, be valid.

fn one() {
let mut line = [0u8, …512];
let mut buf = line.as_mut_slice();

fn append(buf: &mut &mut [u8], v: &[u8]) {
    let len = buf.clone_from_slice(v);
    *buf = buf.slice_from_mut(len);

// error: lifetime of buf is too short to guarantee its contents can be safely reborrowed
// ^~~
// note: buf would have to be valid for the anonymous lifetime #2 defined on the block at 7:45…
// note: …but buf is only valid for the anonymous lifetime #1 defined on the block at 7:45
}

append(&mut buf, b"test");
append(&mut buf, b"foo");

}
The second approach was to give both levels of indirection the same lifetime, e.g. append<'a>(&'a mut &'a mut [u8], v: &[u8]) to try and squelch the error. This didn’t work because I wasn’t allowed to reassign back to *buf, as it considered buf.mut_slice_from(len) to borrow it. I assume the borrow check is tied to the lifetime, which is shared at both levels, so borrowck thinks buf is borrowed when it’s really *buf that’s borrowed.

Curiously, it also decided I couldn’t use &mut buf twice in the calling code, as it seemed to think it was already borrowed.

fn two() {
let mut line = [0u8, …512];
let mut buf = line.as_mut_slice();

fn append<'a>(buf: &'a mut &'a mut [u8], v: &[u8]) {
    let len = buf.copy_from(v);
    *buf = buf.mut_slice_from(len);

// error: cannot assign to *buf because it is borrowed
// ^~~~
// note: borrow of *buf occurs here
// ^~~
}

append(&mut buf, bytes!("test"));
append(&mut buf, bytes!("foo"))

// error: cannot borrow buf as mutable more than once at a time
// ^~~~~~~~
// note: previous borrow of buf as mutable occurs here
// ^~~~~~~~
}
The third approach was to ditch &mut &mut [u8] entirely and try capturing buf in a closure instead. This gave some odd errors. First off, it kept referencing (*buf)[], and I don’t know what it meant by that. Also, the first error here indicates that a borrow on a later line was blocking a borrow on an earlier line, which is quite bizarre. How can buf have been borrowed already when the later line is, well, later? It also considered the same reference to buf to consist of multiple mutable borrows.

fn three() {
let mut line = [0u8, …512];
let mut buf = line.as_mut_slice();

let append = |v: &[u8]| {
    let len = buf.copy_from(v);

// error: cannot borrow (*buf)[] as mutable more than once at a time
// ^~~
buf = buf.mut_slice_from(len);
// note: previous borrow of (*buf)[] as mutable occurs here
// ^~~
// error: cannot borrow (*buf)[] as mutable more than once at a time
// ^~~
// note: previous borrow of (*buf)[] as mutable occurs here
// ^~~
// error: cannot assign to buf because it is borrowed
// ^~~
// note: borrow of buf occurs here
// ^~~
};

append(bytes!("test"));
append(bytes!("foo"));

}
In the end, I couldn’t figure out any way to accomplish what I wanted. It seems to me the first approach should have worked.
Thank you.


#2

It’s a bit hard to reassemble your code to something to run. Posting it to play.rust-lang.org and linking it here might make it easier to people to check them out.


#3

This issue was brought up on github and @nikomatsakis provided an explanation: https://github.com/rust-lang/rust/issues/11361


#4

I’m confused as to why that issue is over three years old, and the OP is almost a direct copy and paste of it.


#5

Because I find that it still a problem for me, and I have free time now, so…you understand.


#6

Did @nikomatsakis’s explanation there help? Your post here starts from square zero but the github issue already has an explanation.