Rust lifetime issue in loop

Viewed 1152

How to get this example to compile without array copying or multiple calls to b() per iteration — b() has to perform some expensive parsing?

This is not the full code that I wrote, but it illustrates the problem I had. Here, Test is attempting to perform some kind of streaming parsing work. c() is the parsing function, it returns Some when parsing was successful. b() is a function that attempts to read more data from the stream when c() can not parse using the available data yet. The returned value is a slice into the self.v containing the parsed range.

struct Test {
    v: [u8; 10],
    index: u8,
}

impl Test {
    fn b(&mut self) {
        self.index = 1
    }

    fn c(i: &[u8]) -> Option<&[u8]> {
        Some(i)
    }

    fn a(&mut self) -> &[u8] {
        loop {
            self.b();

            match Test::c(&self.v) {
                Some(r) => return r,
                _ => continue,
            }
        }
    }
}

fn main() {
    let mut q = Test {
        v: [0; 10],
        index: 0,
    };

    q.a();
}

When compiling, it produces the following borrow checker error:

error[E0502]: cannot borrow `*self` as mutable because `self.v` is also 
borrowed as immutable
  --> <anon>:17:13
   |
17 |             self.b();
   |             ^^^^ mutable borrow occurs here
18 | 
19 |             match Test::c(&self.v) {
   |                            ------ immutable borrow occurs here
...
24 |     }
   |     - immutable borrow ends here

If I change a() to:

fn a(&mut self) -> Option<&[u8]> {
    loop {
        self.b();

        if let None = Test::c(&self.v) {
            continue
        }

        if let Some(r) = Test::c(&self.v) {
            return Some(r);
        } else {
            unreachable!();
        }
    }
}

Then it runs, but with the obvious drawback of calling the parsing function c() twice.

I kind of understand that changing self while the return value depends on it is unsafe, however, I do not understand why is the immutable borrow for self.v is still alive in the next iteration, when we attempted to call b() again.

1 Answers
Related