Cannot use `self....` because it was mutably borrowed

Hi,

I'm new to Rust and I'am following this tutorial here: https://rustwasm.github.io/docs/book/game-of-life/time-profiling.html

So now I try to implement one improvement by myself. I follow one of the suggestions made in the bottom of his page.I try to implement double buffering. Now I got a problem mutable references.

Here is some code:

I did implement the method get_buf_mut, but I can not use it, because I can only borrow mutably once.

 for row in 0..self.height {
 |                           ^^^^^^^^^^^ use of borrowed `*self`

So I guess I need to change the way I'm thinking and change the design of this code here, to make it work with restrictions of rust.

I'm coming from a java/c# background, so this heavily influences how my thinking and problem solving works.

Any suggestions how I can make this work?

You can copy height and width beforehand, then use the copies. That way you won't get overlapping regions of exclusive borrows. (right now readBuf and writeBuf extend the region which self is borrowed exclusively, and you aren't allowed to reuse self in that region. So copying beforehand gets around this by not reusing self in that region)


Please don't post images of code, it makes it harder for me to help you. Please use code fences (as described here to format your code)

Thanks yato, that gets me a little further and I learned something new, of how order matters

However I did not post the entire function, this only postpones the problem.


    fn get_buf_mut(&mut self) -> (& Vec<Cell>, &mut Vec<Cell>) {
        match &self.active_buf {
            One => (& self.cells_buf_two, &mut self.cells_buf_one),
            Two => (& self.cells_buf_one, &mut self.cells_buf_two)
        }
    }

    pub fn tick(&mut self) {
        let _timer = Timer::new("Universe::tick");

        let height = self.height;
        let width = self.width;

        let (readBuf,writeBuf) = self.get_buf_mut();

        {
            let _timer = Timer::new("new generation");
            for row in 0..height {
                for col in 0..width {
                    let idx = self.get_index(row, col);
                    let cell = readBuf[idx];
                    let live_neighbors = self.live_neighbor_count(row, col);

                    let next_cell = match (cell, live_neighbors) {
                        (Cell::Alive, x) if x < 2 => Cell::Dead,
                        (Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
                        (Cell::Alive, x) => Cell::Dead,
                        (Cell::Dead, 3) => Cell::Alive,
                        (otherwise,_) => otherwise,
                    };

                    writeBuf[idx] = next_cell;
                }
            }
        }

        self.switch_active_buffer();
    }

    fn switch_active_buffer(&mut self) {
        self.active_buf = match &self.active_buf {
            One => BufActive::Two,
            Two => BufActive::One
        }
    }

    fn get_index(&self, row: u32, column: u32) -> usize {
        (row * self.width + column) as usize
    }

   fn live_neighbor_count(&self, row: u32, column: u32) -> u8 {
      // ...
   }
}

No I get another error:

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\lib.rs:278:31
    |
272 |         let (readBuf,writeBuf) = self.get_buf_mut();
    |                                  ---- mutable borrow occurs here
...
278 |                     let idx = self.get_index(row, col);
    |                               ^^^^ immutable borrow occurs here
279 |                     let cell = readBuf[idx];
    |                                ------- mutable borrow later used here

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\lib.rs:280:42
    |
272 |         let (readBuf,writeBuf) = self.get_buf_mut();
    |                                  ---- mutable borrow occurs here
...
279 |                     let cell = readBuf[idx];
    |                                ------- mutable borrow later used here
280 |                     let live_neighbors = self.live_neighbor_count(row, col);
    |                                          ^^^^ immutable borrow occurs here

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\lib.rs:328:23
    |
325 |         let (readBuf,writebuf) = self.get_buf_mut();
    |                                  ---- mutable borrow occurs here
...
328 |             let idx = self.get_index(row, col);
    |                       ^^^^ immutable borrow occurs here
329 |             writebuf[idx] = Cell::Alive;
    |             -------- mutable borrow later used here

error: aborting due to 3 previous errors

I was hoping I could get around that whole issue by putting the double buffer in its own struct. But I was wrong. The problem still exists. This is how I changed the code now:

pub struct DoubleBuffer {
    cells_buf_one: Vec<Cell>,
    cells_buf_two: Vec<Cell>,
    active_buf: BufActive
}

#[wasm_bindgen]
pub struct Universe {
    width: u32,
    height: u32,
    buffer: DoubleBuffer
}

impl DoubleBuffer {
    pub fn new(cells: Vec<Cell>) -> Self {
        DoubleBuffer {
            cells_buf_one : Clone::clone(&cells),
            cells_buf_two : cells,
            active_buf : BufActive::One
        }
    }

    pub fn switch_active_buffer(&mut self) {
        self.active_buf = match &self.active_buf {
            One => BufActive::Two,
            Two => BufActive::One
        }
    }

    pub fn get_write_buf_mut(&mut self) -> & mut Vec<Cell> {
        match &self.active_buf {
            One => &mut self.cells_buf_one,
            Two => &mut self.cells_buf_two
        }
    }

    pub fn get_read_buf(& self) -> &  Vec<Cell> {
        match &self.active_buf {
            One => & self.cells_buf_one,
            Two => & self.cells_buf_two
        }
    }

    pub fn get_buf_mut(&mut self) -> (& Vec<Cell>, &mut Vec<Cell>) {
        match &self.active_buf {
            One => (& self.cells_buf_two, &mut self.cells_buf_one),
            Two => (& self.cells_buf_one, &mut self.cells_buf_two)
        }
    }

    pub fn init(&mut self, cells: Vec<Cell>) {
        self.cells_buf_one = Clone::clone(&cells);
        self.cells_buf_two = cells;
    }
}

impl Universe {
   // ... 
    pub fn tick(&mut self) {
        let _timer = Timer::new("Universe::tick");

        let height = self.height;
        let width = self.width;


        let (readBuf,writeBuf) = self.buffer.get_buf_mut();

        {
            let _timer = Timer::new("new generation");
            for row in 0..height {
                for col in 0..width {
                    let idx = self.get_index(row, col);
                    let cell = readBuf[idx];
                    let live_neighbors = self.live_neighbor_count(row, col);

                    let next_cell = match (cell, live_neighbors) {
                        (Cell::Alive, x) if x < 2 => Cell::Dead,
                        (Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
                        (Cell::Alive, x) => Cell::Dead,
                        (Cell::Dead, 3) => Cell::Alive,
                        (otherwise,_) => otherwise,
                    };

                    writeBuf[idx] = next_cell;
                }
            }
        }

        self.buffer.switch_active_buffer();
    }


}
// ...
}

Still same issue

    error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\lib.rs:307:31
    |
301 |         let (readBuf,writeBuf) = self.buffer.get_buf_mut();
    |                                  ----------- mutable borrow occurs here
...
307 |                     let idx = self.get_index(row, col);
    |                               ^^^^ immutable borrow occurs here
308 |                     let cell = readBuf[idx];
    |                                ------- mutable borrow later used here

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\lib.rs:309:42
    |
301 |         let (readBuf,writeBuf) = self.buffer.get_buf_mut();
    |                                  ----------- mutable borrow occurs here
...
308 |                     let cell = readBuf[idx];
    |                                ------- mutable borrow later used here
309 |                     let live_neighbors = self.live_neighbor_count(row, col);
    |                                          ^^^^ immutable borrow occurs here

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\lib.rs:350:23
    |
347 |         let writebuf = self.buffer.get_write_buf_mut();
    |                        ----------- mutable borrow occurs here
...
350 |             let idx = self.get_index(row, col);
    |                       ^^^^ immutable borrow occurs here
351 |             writebuf[idx] = Cell::Alive;
    |             -------- mutable borrow later used here

I would restructure your code a bit to

fn pick_buffer<'a>(active: BufActive, buf_one: &'a mut Vec<Cell>, buf_two: &'a mut Vec<Cell>) -> (&'a Vec<Cell>, &'a mut Vec<Cell>) {
    match active {
        One => (buf_two, buf_one),
        Two => (buf_one, buf_two)
    }
}

// called like

pick_buffer(self.active_buf, &mut self.cells_buf_one, &mut self.cells_buf_two);

So that Rust can reason about the disjoint fields. One way to extract this into a function would be to do something like,

struct Buffer {
    buf_one: Vec<Cell>,
    buf_two: Vec<Cell>,
    active: ActiveBuffer,
}

struct OtherData {
    width: u32,
    height: u32,
}

struct Universe {
    buffer: Buffer,
    other_data: OtherData
}

Then you can do something like,

let (read_buf, write_buf) = self.buffer.get_mut();

self.other_data.get_index(row, col);
self.other_data.live_neightbor_count(row, col);

If you can't split your data like this, then you will have to use the first method of passing data around explicitly.

1 Like

Ok, I see I have to split both parts of the data ...

Thats how I ended up compiling:

    pub fn tick(&mut self) {
        let _timer = Timer::new("Universe::tick");


        let (readBuf,writeBuf) = self.buffer.get_buf_mut();

        {
            let _timer = Timer::new("new generation");
            for row in 0..self.dimension.height {
                for col in 0..self.dimension.width {
                    let idx = self.dimension.get_index(row, col);
                    let cell = readBuf[idx];
                    let live_neighbors = Universe::live_neighbor_count(&self.dimension, readBuf, row, col);
                    //
                    // log!("cell[{}, {}] is initially {:?} and has {} live neighbors",
                    //     row, col, cell, live_neighbors);

                    let next_cell = match (cell, live_neighbors) {
                        (Cell::Alive, x) if x < 2 => Cell::Dead,
                        (Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
                        (Cell::Alive, x) => Cell::Dead,
                        (Cell::Dead, 3) => Cell::Alive,
                        (otherwise,_) => otherwise,
                    };

                    writeBuf[idx] = next_cell;
                }
            }
        }

        let _timer = Timer::new("free old cells");

        self.buffer.switch_active_buffer();
    }


}

Here is the entire code (not cleaned up, its a mess, It's still buggy, but it compiles :wink:
https://pastebin.com/F36MEiFS

I kept live_neighbor_count within the implementation of struct Universe as I thought that it would make more sense there.

Thanks for your help Yato. Now I need to think about that and wrap my head arround the borrow checker.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.