0

I have a struct that represents a TCP stream, over which I am recieving protobuf encoded messages. The struct impl includes a read_event method that reads the raw data of the message into a buffer, decodes it, and returns the decoded message. I am using quick-protobuf, and the decoded struct contains references to the raw data in the buffer in order to minimize copies and allocations.

I have another function which contains a loop. Inside the loop, it repeatedly calls read_event and checks the returned message for a specific condition. When the condition is met, it exits the function, returning the message. If the condition is not met, it discards the message and continues around the loop.

My problem is that I can't seem to return the message from this second function without angering the borrow checker.

I have made an MCVE below:

struct Event<'a> {
    u8ref: &'a u8
}

struct EventStream {
    buf: Vec<u8>,
}

impl EventStream {
    fn read_event<'a>(&'a mut self) -> Event<'a> {
        todo!()
    }
}

struct Processor {
    stream: EventStream,
}

impl Processor {
    fn find_it<'a>(&'a mut self) -> Event<'a> {
        loop {
            match self.stream.read_event() {
                event if *event.u8ref == 0x80 => return event,
                _ => {}
            }
        }
    }
}

fn main() {}

Playground Link

The real code is of course much more complex - I have left out the protobuf decoding, the stream reader is async, the loop contains other elements, and the matching condition is much more complex, but the nub of the problem is this error:

error[E0499]: cannot borrow `self.stream` as mutable more than once at a time
  --> src/main.rs:22:19
   |
20 |     fn find_it<'a>(&'a mut self) -> Event<'a> {
   |                -- lifetime `'a` defined here
21 |         loop {
22 |             match self.stream.read_event() {
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ `self.stream` was mutably borrowed here in the previous iteration of the loop
23 |                 event if *event.u8ref == 0x80 => return event,
   |                                                         ----- returning this value requires that `self.stream` is borrowed for `'a`

For more information about this error, try `rustc --explain E0499`.

I have tried:

  • Separating the EventStream from the Processor and passing the EventStream in as a separate argument.
  • Passing the buffer in as a separate argument

How can I structure this so that I can re-use the same buffer inside the loop, returning the message that matched the condition, and of course also ensuring that borrow on the EventStream lives as long as the returned Event?

harmic
  • 28,606
  • 5
  • 67
  • 91
  • possible solution https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f96953ab8baa4286becc8b2f56622698 – Stargateur Jun 17 '22 at 01:50
  • 1
    Thanks @Stargateur. Actually [this](https://stackoverflow.com/questions/50519147/double-mutable-borrow-error-in-a-loop-happens-even-with-nll-on) is probably a better dupe. – harmic Jun 17 '22 at 02:01
  • the dup I choice link several questions that include your link but I add it anyway – Stargateur Jun 17 '22 at 03:31
  • Also, don't use `&'a mut self`. References to `self` already have the implicit lifetime `'_`; just do `fn find_it(&mut self) -> Event<'_>`. – Finomnis Jun 17 '22 at 08:10

0 Answers0