0

I have a struct:

pub struct CommunityContents {
    pub friends: RefCell<HashMap<FriendID, FriendData>>, 
    pub index: RefCell<HashMap<u64, BTreeMap<FriendID, FriendData>>>, 
    pub authenticated: bool,
    pub age: u64,     
    pub height: u64,
}

Which is protected with a RwLock with a parent struct:

pub struct Community {
    pub community_contents: RwLock<CommunityContents>,
}

pub struct FriendData {
    pointer: Rc<Data>,
}

pub struct Data {
    pub key: Key,
    pub friend_ids: Vec<FriendID>,
}

I want to be able to modify the data inside index. I have no problems inserting data into index doing write() to CommunityContents and a borrow_mut().insert(…) for the BtreeMap inside index.

My problem is deleting elements from BtreeMap, given FriendID. My rough attempt is:

pub fn delete_family(community: &Self, friend_id: FriendID) {
    //get community contents
    let mut g = community.community_contents.write().expect("Lock is poisoned");
    //get friend from inside friends name of community contents
    let mut friend = g.friends.borrow_mut().get(&friend_id).unwrap().pointer.clone();
    // get id attri
    let mut friend_key = friend.key;
    let mut a = g.index.borrow_mut().get(&friend_key);
    let mut c = a.unwrap();
    c.remove(&friend_id);
}

And I get the error cannot borrow as mutable. I've tried various things which has made my code above a bit messy.

Edit: sorry I missed out the FriendData and Data structs in my question.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Gman man
  • 475
  • 1
  • 4
  • 8
  • Please provide the exact error. Also consider removing fields and types that are not relevant to the problem, to create a [reprex]. – Peter Hall Aug 04 '19 at 23:26

1 Answers1

1

After making some guesses about the missing types from your example code, I see two errors:

error[E0716]: temporary value dropped while borrowed
  --> src/lib.rs:37:21
   |
37 |         let mut a = g.index.borrow_mut().get(&friend_key);
   |                     ^^^^^^^^^^^^^^^^^^^^                 - temporary value is freed at the end of this statement
   |                     |
   |                     creates a temporary which is freed while still in use
38 |         let mut c = a.unwrap();
   |                     - borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

error[E0596]: cannot borrow `*c` as mutable, as it is behind a `&` reference
  --> src/lib.rs:39:9
   |
38 |         let mut c = a.unwrap();
   |             ----- help: consider changing this to be a mutable reference: `&mut std::collections::BTreeMap<u64, FriendData>`
39 |         c.remove(&friend_key);
   |         ^ `c` is a `&` reference, so the data it refers to cannot be borrowed as mutable

The first one can be fixed by following the suggestion - use a new variable to ensure that the temporary value (underlined in the error message) lives long enough:

let mut tmp = g.index.borrow_mut();
let mut a = tmp.get(&friend_key);

Now the borrowed value, tmp lives right to the end of the function, outliving a which needs to borrow from it.

The second error and suggestion might be harder to understand. a is an Option<&BTreeMap> but after unwrapping it you are trying to mutate it, so that reference needs to be mutable. The Option<&BTreeMap> comes from the call to get, so you need to find a way to get a mutable reference instead. you can do that with a different method, get_mut, which will return the Option<&mut BTreeMap> that you need:

let mut tmp = g.index.borrow_mut();
let mut a = tmp.get_mut(&friend_key);
Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • That makes perfect sense and thanks for the explanation to clarify. One other quick thing if you don't mind, do you think the RwLock on the struct makes the RefCells unnecessary? I wonder if I went overkill there. – Gman man Aug 05 '19 at 09:28