Help about multiple mutable borrows

Hi,

I'm new to Rust and I'm trying to write a miniflow data struct used in open vswitch. I'm stuck at this error due to multiple mutable borrows. Any suggestion or things to read are welcome. Thanks!

use std::usize;
struct flowmap {
    bits: [u64; FLOWMAP_UNITS],
}

pub const FLOWMAP_UNITS:usize = 2;
pub const MAP_T_BITS:usize = 64;
pub const FLOW_U64S:usize = 84;

impl flowmap {
    pub fn new() -> flowmap {
        flowmap { 
            bits: [0; FLOWMAP_UNITS],
        }
    }
}

struct miniflow {
    pub map: flowmap,   // a bitmap
    pub values: [u64; FLOW_U64S],
}

impl miniflow {
    pub fn new() -> miniflow {
        miniflow {
            map: flowmap::new(), 
            values: [0; FLOW_U64S],
        }   
    }   
}

/* Context for pushing data to a miniflow. */
struct mf_ctx<'a> {
    map: flowmap,
    data: &'a mut [u64], 
    //end: &'a mut [u64], // cause multiple mutable borrow: XD
}

impl<'a> mf_ctx<'a> {
    pub fn from_mf(map_: flowmap, data_: &'a mut [u64]) -> mf_ctx<'a> {
        mf_ctx {
            map: map_, 
            data: data_,
        }
    }   

    pub fn miniflow_push_uint64_(&'a mut self, ofs: usize, value: u64) {
        self.data[0] = value;
        self.data = &mut self.data[1..]; // move self.data to next u64  
    }   
}

fn main() {
    println!("Hello, world!");

    let mut mf: miniflow = miniflow::new(); 
    let mut mfx = &mut mf_ctx::from_mf(mf.map, &mut mf.values);
    
    let ofs = 0;
    mfx.miniflow_push_uint64_(ofs, 1234);
    mfx.miniflow_push_uint64_(ofs + 1, 1234);
}

I got error saying below, but I though I'm not creating another mutable borrower? I'm reusing the same one 'mfx', so I don't understand why this is an error...

error[E0499]: cannot borrow `*mfx` as mutable more than once at a time
   --> src/main.rs:104:5
    |
103 |     mfx.miniflow_push_uint64_(ofs, 1234);
    |     --- first mutable borrow occurs here
104 |     mfx.miniflow_push_uint64_(ofs + 1, 1234);
    |     ^^^
    |     |
    |     second mutable borrow occurs here
    |     first borrow later used here

Ah that's an unfortunate pitfall. You need to change &'a mut self to &mut self.

The reason it fails is that when you specify the lifetime 'a explicitly like that, you're saying that this function borrows the value for as long as that lifetime lives, but since this lifetime refers to the lifetime of the data inside itself, the borrow lasts as long as the value itself does.

One case where you'd want to use the 'a lifetime explicitly is if you want to have a function that replaces the value in the data field inside the struct. Of course, to put a new reference into that field, that reference needs to be using the 'a lifetime explicitly, as you would otherwise not be able to store it somewhere that exists after the function returns.

3 Likes

Hi Alice,

Thanks for your quick reply!
I try it but then hit another error which looks more confusing ...
so remove the 'a

    pub fn miniflow_push_uint64_(&mut self, ofs: usize, value: u64) {
        self.data[0] = value;
        self.data = &mut self.data[1..]; // move self.data to next u64  
    }   

and

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/main.rs:57:26
   |
57 |         self.data = &mut self.data[1..]; // move self.data to next u64  
   |                          ^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 55:5...
  --> src/main.rs:55:5
   |
55 | /     pub fn miniflow_push_uint64_(&mut self, ofs: usize, value: u64) {
56 | |         self.data[0] = value;
57 | |         self.data = &mut self.data[1..]; // move self.data to next u64  
58 | |     }   
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:57:26
   |
57 |         self.data = &mut self.data[1..]; // move self.data to next u64  
   |                          ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 47:6...
  --> src/main.rs:47:6
   |
47 | impl<'a> mf_ctx<'a> {
   |      ^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:57:21
   |
57 |         self.data = &mut self.data[1..]; // move self.data to next u64  
   |                     ^^^^^^^^^^^^^^^^^^^

I think the easiest approach is to store an IterMut. You can call next on it which returns a mutable reference to the first element and increments the internal counter by one.

While this sounds like something that should be able to be done in an easier way, I can't find it.

It turns out you can do this.

1 Like

Thanks a lot for your help!