Search code examples
rustlifetime

How to fill a buffer in an struct and display it at the same time?


I'm having trouble with the lifetime of a buffer.

I want my main program to be responsible to fill a struct and a buffer. My struct fills the buffer in an "infinite" loop. For each iteration of the loop, I want to print the buffer content. Something like this:

fn main() {
    let mut buffer = [0.0; 1024];
    let mut obj = MyObject::new(&mut buffer);
    loop {
        obj.fill_buffer();
        for i in 0..1024 {
            println!("Sample {}: {}", i, buffer[i]);
        }
    }
}

My struct looks like this:

struct MyObject<'a> {
    a_value: f64,
    buffer: &'a mut [f64],
}

impl<'a> MyObject<'a> {
    fn new(buffer: &'a mut [f64]) -> MyObject<'a> {
        MyObject { a_value: 1.0, buffer: buffer }
    }

    fn fill_buffer(&mut self) {
        for i in 0..self.buffer.len() {
            self.buffer[i] = 1.0;
        }
    }
}

From the error messages "cannot borrow buffer as immutable because it is also borrowed as mutable" and things like this which depends on my tests and rust documentation, I understand that the problem comes from that I display buffer just after the call fill_buffer. fill_buffer uses a reference and it seems to pose a problem to rust to call it and to get value just after in the same scope.

How can I have an infinite loop that calls fill_buffer on the struct and displays it just after? I want main to be responsible for creating the buffer. And I want the buffer to be in the struct, not passed as parameter to fill_buffer.

EDIT Here is the code corrected with accepted answer of kmdreko:

struct MyObject<'a> {
    a_value: i64,
    buffer: &'a mut [f64],
}

impl<'a> MyObject<'a> {
    fn new(buffer: &'a mut [f64]) -> MyObject<'a> {
        MyObject { a_value: 0, buffer: buffer }
    }

    fn fill_buffer(&mut self) -> &[f64] {
        for i in 0..self.buffer.len() {
            self.buffer[i] = i as f64 * self.a_value as f64;
        }

        self.buffer
    }
}

fn main() {
    let mut buffer = [0.0; 8];
    let mut obj = MyObject::new(&mut buffer);
    for i in 1..9 {
        obj.a_value = i;
        let buffer = obj.fill_buffer();
        for j in 0..8 {
            println!("Loop {}: subloop: {}: sample {}", i, j, buffer[j]);
        }
    }
}

Solution

  • You have given exclusive access of buffer to obj by holding a mutable reference, so main() can't access buffer while obj has it.

    I see two options:

    • re-create obj on each iteration of the loop, so it may be destroyed (releasing its exclusive access) before printing at the end, or

    • borrow the buffer back:

      impl<'a> MyObject<'a> {
          fn buffer(&self) -> &[f64] {
              self.buffer
          }
      }