1

I think this is best explained with this code upfront:

struct Borrowed<'a>(&'a Buf);
struct Buf;
impl Buf {
    fn adapt(&mut self) {}
}

fn borrow(buf: &mut Buf) -> Option<Borrowed> {
    buf.adapt(); // think Vec::resize(), so we do need a mutable borrow initially
    // When done, we keep a shared borrow, but borrowchk doesn't know about that apparently
    Some(Borrowed(buf))
}


fn locate<'a>(buf: &'a mut Buf) -> Option<Borrowed<'a>> {
    for _c in 1..3 {
        // This works!
        // if _c % 2 == 0 {
        //   return borrow(buf); 
        // }
        // This also works but is wasteful
        // if borrow(buf).is_some() {
        //     return borrow(buf);
        // }
        if let Some(b) = borrow(buf) {
            return Some(b)
        }
    }
    None
}

fn main() {
    locate(&mut Buf);
}

Here is the playground link for the code above, which doesn't borrowcheck:

error[E0499]: cannot borrow `*buf` as mutable more than once at a time
  --> src/main.rs:24:33
   |
14 | fn locate<'a>(buf: &'a mut Buf) -> Option<Borrowed<'a>> {
   |           -- lifetime `'a` defined here
...
24 |         if let Some(b) = borrow(buf) {
   |                                 ^^^ mutable borrow starts here in previous iteration of loop
25 |             return Some(b)
   |                    ------- returning this value requires that `*buf` is borrowed for `'a`

I have found a similar problem referenced in a GitHub issue (but can't find it now) which indicates this is a known limitation of NLL for performance reasons.

What is a workaround for this that isn't wasteful and maintains a buffer that is passed in?

Due to this, right now I have to make an expensive pack lookup twice as a workaround.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Byron
  • 3,908
  • 3
  • 26
  • 35

0 Answers0