0

I'm encountering a borrow checker issue in Rust where I am attempting to modify a Vec<u8> within a loop using splice, and then obtain a reference to the same Vec immediately afterwards. The error only occurs within the loop, as removing the loop resolves the issue. Below is the minimal code snippet that reproduces the error:

pub struct bz_stream_DState<'a> {
    pub next_in: Option<&'a [u8]>,
    pub state: *mut DState<'a>,
}

impl<'a> bz_stream_DState<'a> {
    pub fn set_next_in(&mut self, buf: &'a [u8]) {
        self.next_in = Some(buf);
    }
}

pub struct bzFile<'a> {
    pub buf_vec: Vec<u8>,
    pub strmD: bz_stream_DState<'a>,
}

pub struct DState<'a> {
    pub strm: *mut bz_stream_DState<'a>,
}

fn main() {
    let mut bzf = bzFile {
        buf_vec: vec![1, 2, 3, 4, 5],
        strmD: bz_stream_DState {
            next_in: None,
            state: std::ptr::null_mut(),
        },
    };

    for _i in 1..6 {
        let range = 0..1;
        let new_elements = [10, 11, 12];
        bzf.buf_vec.splice(range, new_elements.iter().cloned());
        let temp_buf_vec_ref = &bzf.buf_vec;
        bzf.strmD.set_next_in(temp_buf_vec_ref);
    }
}

The error message I receive is: (seen in rust playground)

error[E0502]: cannot borrow `bzf.buf_vec` as mutable because it is also borrowed as immutable
  --> src/main.rs:35:9
   |
35 |         bzf.buf_vec.splice(range, new_elements.iter().cloned());
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
39 |         let temp_buf_vec_ref = &bzf.buf_vec;
   |                                ------------
   |                                |
   |                                immutable borrow occurs here
   |                                immutable borrow later used here

The key point to note is that if I remove the for loop, the error does not occur. I've tried to separate the mutable and immutable borrows by introducing a new block scope within the loop, but it hasn't resolved the issue. Could someone help explain why the borrow checker is still not satisfied within the loop context and how to fix this error?

Additionally, if there are any improvements that could be made to the code structure to avoid such borrow checker issues, especially within loops, I would appreciate suggestions on that as well.

Context Background

I am trying to rewrite the original C code of bzip2 into Rust, notice the modification of bzf in the lines

Notice C code within while loop It first read

 n = fread ( bzf->buf, sizeof(UChar), 
                     BZ_MAX_UNUSED, bzf->handle );

Then we translated to Rust code to

 match handle.read(&mut bzf.buf_vec[total_read..]) {

using library below

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.read(buf)
    }

Then we use pub next_in: Option<&'a [u8]> to imitate the behavior of the array pointer in C

5
  • Notice that Vec::splice() returns an iterator, and bzf.buf_vec.splice(..); doesn't actually use that iterator at all. So the code as written degenerates to removing range from the buf_vec. Commented Jan 21, 2024 at 14:24
  • You can't modify bzf while you hold a shared reference to it, the first loop stores a reference to bzf in bzf, afterwards you can't modify it no more, the loop is irrelevant, doing the things you're trying to do twice is What you're trying to do is very unidiomatic, as storing a reference in the value itself is highly problematic Commented Jan 21, 2024 at 14:39
  • "to imitate the behavior of the array pointer in C" – Do yourself a favor and don't try to write C in Rust, that's only going to cause headaches and lead to bad performance or bugs. The equivalent of a C pointer is *mut u8 in Rust, for obvious reasons we try to avoid it though. Commented Jan 21, 2024 at 15:09
  • Do you recommend use Rc/RefCell to rewrite? @cafce25 In this rewrite version of decompress, it seems use Arc and Threadpool to imitate the read process. Commented Jan 21, 2024 at 15:36
  • Is that possible to use move to move the ownership alternatively between mutable reference and shared reference? Commented Jan 22, 2024 at 9:31

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.