'How to return a reference to a value owned by a Vec within a Rc<RefCell<_>>? [duplicate]

Assume following code

pub struct Universe {
    components: Rc<RefCell<Vec<Component>>>,
    active_component: Rc<RefCell<Option<usize>>>,
}

I would like to introduce a convenience method that returns a mutable reference to the active component, e.g.

fn get_active_component(&mut self) -> Option<&mut Component> {
    if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
        let i = *active_component_idx;
        return self.components.borrow_mut().get_mut(i);
    }

    Option::None
}

which results in error

145 |             return self.components.borrow_mut().get_mut(i);
    |                    ----------------------------^^^^^^^^^^^
    |                    |
    |                    returns a reference to data owned by the current function
    |                    temporary value created here

I do understand the error. The borrow_mut() creates a temporary variable which goes out of scope after the function returns. But I have absolutely no idea how you would realize such a method in rust apart from always inlining the code.



Solution 1:[1]

The standard way would be to mimic what RefCell does -- return a proxy struct wrapping the RefMut from .borrow_mut() and containing the vector index, implementing Deref and DerefMut.

pub struct ComponentHandle<'a> {
    vecref: RefMut<'a, Vec<Component>>,
    index: usize,
}

impl Deref for ComponentHandle<'_> {
    type Target = Component;
    
    fn deref(&self) -> &Component {
        // SAFETY: We already verified the index is valid, RefCell won't
        // dispense another mutable reference while we hold the RefMut, and we
        // don't modify the vector's length, so we know this index is valid.
        unsafe { self.vecref.get_unchecked(self.index) }
    }
}

impl DerefMut for ComponentHandle<'_> {
    fn deref_mut(&mut self) -> &mut Component {
        // SAFETY: We already verified the index is valid, RefCell won't
        // dispense another mutable reference while we hold the RefMut, and we
        // don't modify the vector's length, so we know this index is valid.
        unsafe { self.vecref.get_unchecked_mut(self.index) }
    }
}

impl Universe {
    fn get_active_component(&mut self) -> Option<ComponentHandle<'_>> {
        if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
            let vecref = self.components.borrow_mut();
            let index = *active_component_idx;
            
            if index < vecref.len() {
                return Some(ComponentHandle { vecref, index });
            }
        }
        
        None
    }
}

Alternatively, this function could accept a closure to invoke, passing it the bare reference. This is simpler to code, though less idiomatic:

fn get_active_component<F>(&mut self, f: F)
    where F: FnOnce(Option<&mut Component>)
{
    if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
        let i = *active_component_idx;
        f(self.components.borrow_mut().get_mut(i));
    } else {
        f(None);
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1