Which traits allow the following code to work the way it does?


#1

In the following code sample I’m curious how the borrow_mut() calls are routed to the correct object. Is it because of the Deref trait and deref coercion?

use std::rc::Rc;
use std::cell::RefCell;

#[derive(Debug)]
struct Foo {

}

impl Foo {
    fn take_foo_by_self(&mut self) {
        println!("took {:?} by self", self)
    }
}

#[derive(Debug)]
struct ContainsFoo {
    foo: Rc<RefCell<Box<Foo>>>,
}

fn take_foo(foo: &mut Foo) {
    println!("took {:?} explicitly", foo)
}

fn main() {
    let f = Foo { };
    let rc = Rc::new(RefCell::new(Box::new(f)));
    
    let cf0 = ContainsFoo { foo: rc.clone() };
    let cf1 = ContainsFoo { foo: rc.clone() };
    
    take_foo(&mut cf0.foo.borrow_mut()); // <--- How does this function call work?
    cf1.foo.borrow_mut().take_foo_by_self(); // <--- and this?
}

Rust playground link: https://is.gd/CXjmWr


Cannot understand why E0277 is triggered here:
#2

Yep, the .borrow_mut() call is routed through Rc's Deref implementation, and then &mut RefMut<Foo> is coerced to &mut Foo though RefMut's DerefMut implementation.

Basically the same deal in the second line, though in that case there are no coercions, just calls to Rc's and RefMut's Deref and DerefMut implementations.


#3

Thanks @sfackler - that clarified things a lot.