2

I'm puzzled by this error. According to my code, bytes is either returned, so the problematic code is not reached, or it's dropped, so it shouldn't matter. Why doesn't the borrow checker accept this code, and how might I modify it so it would compile?

See: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b3ec3bd043fbeff133fa13915ab5dcd3

   Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*data` as mutable because it is also borrowed as immutable
  --> src/main.rs:51:5
   |
41 | fn read_helper<'a>(data: &'a mut BufList, temp: &'a mut Vec<u8>, len: usize) -> Result<&'a [u8], Error> {
   |                -- lifetime `'a` defined here
42 |     {
43 |         let bytes = data.peek_bytes().ok_or(Error::EOF)?;
   |                     ----------------- immutable borrow occurs here
...
46 |             return Ok(&bytes[..len]);
   |                    ----------------- returning this value requires that `*data` is borrowed for `'a`
...
51 |     data.read_bytes(temp, len)?;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
use std::cell::Cell;

#[derive(Debug)]
pub struct BufList {
    buffer: Vec<u8>,
    pos: Cell<usize>,
}

// This is contrived, just to make this a self-contained example
impl BufList {
    pub fn new() -> Self {
        BufList { buffer: Vec::new(), pos: Cell::new(0) }
    }

    pub fn peek_bytes(&self) -> Option<&[u8]> {
        if self.pos.get() < self.buffer.len() {
            Some(&self.buffer[self.pos.get()..])
        } else {
            None
        }
    }

    pub fn advance(&self, len: usize) {
        self.pos.set(self.pos.get() + len);
    }

    pub fn read_bytes(&mut self, vec: &mut Vec<u8>, len: usize) -> Result<(), Error> {
        if self.pos.get() + len <= self.buffer.len() {
            vec.extend_from_slice(&self.buffer[self.pos.get()..self.pos.get() + len]);
            Ok(())
        } else {
            Err(Error::EOF)
        }
    }
}

#[derive(Debug)]
pub enum Error {
    EOF,
}

fn read_helper<'a>(data: &'a mut BufList, temp: &'a mut Vec<u8>, len: usize) -> Result<&'a [u8], Error> {
    {
        let bytes = data.peek_bytes().ok_or(Error::EOF)?;
        if len <= bytes.len() {
            data.advance(len);
            return Ok(&bytes[..len]);
        }
    }

    temp.clear();
    data.read_bytes(temp, len)?;
    Ok(&temp[..])
}

fn main() {
    let mut buf_list = BufList::new();
    buf_list.buffer = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let mut temp = Vec::new();
    let len = 5;

    match read_helper(&mut buf_list, &mut temp, len) {
        Ok(data) => println!("Data: {:?}", data),
        Err(e) => println!("Error: {:?}", e),
    }
}

Eloff
  • 20,828
  • 17
  • 83
  • 112
  • 2
    Does this answer your question? [Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?](https://stackoverflow.com/questions/38023871/returning-a-reference-from-a-hashmap-or-vec-causes-a-borrow-to-last-beyond-the-s) You are hitting the same limitation in the borrow checker. – cdhowie May 18 '23 at 22:17
  • @cdhowie That does look like the problem, but it doesn't offer a solution for my case. I think this question could still have its own answer. – Eloff May 19 '23 at 01:46

0 Answers0