Rc and RefCell within parent / child struct relationship

I'm having trouble working with Rc and RefCell.
I would like to be able to

  1. Call the child's render method from the parent.
  2. Be able to update either structs "count" member using the set_state method implemented for each struct. The code that executes the set_state will be run async by a rust wasm event handler so the closure needs to have access to a mutable reference to the struct itself.
use std::cell::RefCell;
use std::rc::Rc;


#[derive(Debug, Default, Clone)]
pub struct Main {
    pub child: Rc<RefCell<MainChild>>,
    pub count: i32,
}

impl Main {
    pub fn create() -> Rc<RefCell<Self>> {
        let main = Main {
            child: MainChild::create(),
            count: 0,
        };
        Rc::new(RefCell::new(main))
    }

    pub fn set_state(&mut self, new_count: i32) {
        use std::borrow::BorrowMut;
        self.borrow_mut().count += new_count;
        self.borrow_mut().render();
    }

    pub fn render(&mut self) {
        use std::borrow::BorrowMut;
  
        let clone = Rc::clone(self.borrow_mut());

// This closure will be executed by an event handler in rust wasm but I left that code out for //simplicity.
        let closure = Box::new(move || clone.set_state(2));
        self.borrow_mut().child.borrow_mut().render();
// render something that displays self.count
    }
}

#[derive(Debug, Default, Clone)]
pub struct MainChild {
    pub count: i32,
}

impl MainChild {
    pub fn create() -> Rc<RefCell<Self>> {
        let child = MainChild { count: 0 };
        Rc::new(RefCell::new(child))
    }

    pub fn set_state(&mut self, new_count: i32) {
        use std::borrow::BorrowMut;

        self.borrow_mut().count += new_count;
        self.borrow_mut().render();
    }

    pub fn render(&mut self) {
        
        // render something that displays self.count
    }
}

pub fn main() {
    let main = Main::create();
    main.borrow_mut().render();
}

I get multiple errors indicating the struct's implemented methods cannot be found.

  --> src/main.rs:29:31
   |
29 |         let clone = Rc::clone(self.borrow_mut());
   |                               ^^^^^^^^^^^^^^^^^ expected struct `std::rc::Rc`, found struct `Main`
   |
   = note:      expected reference `&std::rc::Rc<_>`
           found mutable reference `&mut Main`

error[E0599]: no method named `set_state` found for struct `std::rc::Rc<_>` in the current scope
  --> src/main.rs:30:46
   |
30 |        

error[E0599]: no method named `render` found for mutable reference `&mut std::rc::Rc<std::cell::RefCell<MainChild>>` in the current scope
  --> src/main.rs:31:46
   |
31 |         self.borrow_mut().child.borrow_mut().render();
   |                                              ^^^^^^ method not found in `&mut std::rc::Rc<std::cell::RefCell<MainChild>>`

Rc::clone can only clone the outer Rc wrapper type, not the cell inside it, and not the temporary proxy object that borrow_mut() returns. Rc::clone(self) should work.

I removed some code and what is being printed to the console illustrates the issue better

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

#[derive(Debug, Default, Clone)]
pub struct Main {
    pub child: Rc<RefCell<MainChild>>,
    pub count: i32,
}

impl Main {
    pub fn create() -> Rc<RefCell<Self>> {
        let main = Main {
            child: MainChild::create(),
            count: 0,
        };
        Rc::new(RefCell::new(main))
    }

    pub fn render(&mut self) {
        use std::borrow::BorrowMut;
        println!("{:?}", self);
        println!("{:?}", self.child);
        println!("{:?}", self.child.borrow_mut());
        // self.child.borrow_mut().render();
    }
}

#[derive(Debug, Default, Clone)]
pub struct MainChild {
    pub count: i32,
}

impl MainChild {
    pub fn create() -> Rc<RefCell<Self>> {
        let child = MainChild { count: 0 };
        Rc::new(RefCell::new(child))
    }

    pub fn render(&mut self) {
        println!("{:?}", self);
    }
}

pub fn main() {
    let main = Main::create();
    main.borrow_mut().render();
}

prints out

Main { child: RefCell { value: MainChild { count: 0 } }, count: 0 }
RefCell { value: MainChild { count: 0 } }
RefCell { value: MainChild { count: 0 } }

So one issue is that within Main's render self is not equal to Rc<RefCell<Self>> but is instead equal to the struct Main. This makes sense to me now. It does throw a wrench in my plans of passing.a Rc::clone of self to a closure from within Main's render method.

The second issue persists. self.child.borrow_mut() does not give me MainChild but instead RefCell { value: MainChild { count: 0 } }. It's like I cannot get the value from inside the RefCell for some reason

This works but I'm not sure it will help me with my original goal of not cloning self when calling self.set_state from within a closure.

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

#[derive(Debug, Default, Clone)]
pub struct Main {
    pub child: Rc<RefCell<MainChild>>,
    pub count: i32,
}

impl Main {
    pub fn create() -> Self {
        let main = Main {
            child: MainChild::create(),
            count: 0,
        };
        main
    }

    pub fn render(&mut self) {
        let child = &*self.child;
        child.borrow_mut().render();
    }
}

#[derive(Debug, Default, Clone)]
pub struct MainChild {
    pub count: i32,
}

impl MainChild {
    pub fn create() -> Rc<RefCell<Self>> {
        let child = MainChild { count: 0 };
        Rc::new(RefCell::new(child))
    }

    pub fn render(&mut self) {
        println!("{:?}", self);
    }
}

pub fn main() {
    let mut main = Main::create();
    main.render();
}

You can use a wrapper struct to add your own methods to Rc<RefCell<...>>:

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

#[derive(Debug, Default, Clone)]
pub struct Handle<T>(Rc<RefCell<T>>);

#[derive(Debug, Default, Clone)]
pub struct Main {
    pub child: Handle<MainChild>,
    pub count: i32,
}

impl Main {
    pub fn create() -> Handle<Self> {
        let main = Main {
            child: MainChild::create(),
            count: 0,
        };
        Handle(Rc::new(RefCell::new(main)))
    }
}

impl Handle<Main> {
    pub fn render(& self) {
       // use std::borrow::BorrowMut;
        println!("{:?}", self);
        println!("{:?}", self.0.borrow().child);
       // println!("{:?}", self.child.borrow_mut());
        self.0.borrow().child.render();
    }
}

#[derive(Debug, Default, Clone)]
pub struct MainChild {
    pub count: i32,
}

impl MainChild {
    pub fn create() -> Handle<Self> {
        let child = MainChild { count: 0 };
        Handle(Rc::new(RefCell::new(child)))
    }
}

impl Handle<MainChild> {
    pub fn render(& self) {
        self.0.borrow_mut().count += 1;
        println!("{:?}", self);
    }
}

pub fn main() {
    let main = Main::create();
    main.render();
}

(Playground)

1 Like

This looks promising. I'm working on implementing this into the actual code. One obstacle is that render and create already belong to a "Component" trait (did not post that part of the code).

Thanks everyone. I'm going with @2e71828 's suggestion of using a wrapper struct because it did solve my original problem.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.