ripytide
ripytide

Reputation: 355

Turning a RefMut into a &mut

use std::cell::RefCell;
use std::rc::Weak;

struct Elem {
    attached_elem: Weak<RefCell<Elem>>,
    value: i32,
}

impl Elem {
    fn borrow_mut_attached_elem(&self) -> &mut Elem {
        //what should this line be?
        self.attached_elem.upgrade().unwrap().borrow_mut()
    }
}

fn main(){}

I have tried some similar other lines but nothing has worked so far, even the experimental cell_leak feature for RefMut.

I don't mind changing the signature of the function I just want to reduce the overhead of getting a mutable reference to the attached_elem from an Elem.

Upvotes: 4

Views: 3730

Answers (1)

user4815162342
user4815162342

Reputation: 155246

what should this line be?

There is nothing you can put in that line to (safely) satisfy the function signature - and that's for good reason. While RefCell does allow obtaining &mut T from a RefCell<T> (that's why it exists), it must guarantee that only one mutable reference exist at a time. It does so by only providing a temporary reference whose lifetime is tied to the RefMut<T> wrapper. Once the wrapper is dropped, the value is marked as no longer borrowed, so the reference must not outlive it.

If Rust were to allow you to return a naked &mut Elem, you'd be able to use the reference after the RefCell has ceased being marked as borrowed. In that case, what's to stop you from calling borrow_mut_attached_elem() again, and obtain a second mutable reference to the same Elem?

So you'll definitely need to change the signature. If you just need to give outside code temporary access to &mut Elem, the easiest way is to accept a closure that will receive it. For example:

fn with_attached_elem<R>(&self, f: impl FnOnce(&mut Elem) -> R) -> R {
    let rc = self.attached_elem.upgrade().unwrap();
    let retval = f(&mut *rc.borrow_mut());
    retval
}

You'd call it to do something with the element, e.g.:

elem.with_attached_elem(|e| e.value += 1);

with_attached_elem takes care to return the value returned by the closure, allowing you to collect data from &mut Elem and propagate it to the caller. For example, to pick up the value of the attached element you could use:

let value = elem.with_attached_elem(|e| e.value);

Upvotes: 7

Related Questions