rustrcrefcell

Rc/RefCell with parent of same struct


I'm trying to convert some object oriented code into Rust. It was going okay until I ran into this situation.

struct A {
    root: Rc<RefCell<B>>,
}

struct B {
    parent: Weak<RefCell<B>>,
    c_lst: Vec<C>
    value: u32
}

struct C {
    parent: Weak<RefCell<B>>,
    b_lst: Vec<Rc<RefCell<B>>>,
    end: bool
}

I have three structs. I want to have a main struct (A here) hold a root of struct B. B and C need to access parent values as read only, but where the first Rc occurs they need to be mutable.

At start this function is called:

impl A {
    fn register(&mut self) {
        for c in self.root.borrow_mut().c_lst {
            c.parent = Rc::downgrade(&self.root);
        }
    }
}

Then I use an update function on A:

impl A {
    fn update(&mut self) {
        self.root.borrow_mut().update();
    }
}

impl B {
    fn update(&mut self) {
        for c in &mut self.c_lst {
            c.update();
        }
    }
}

impl C {
    fn update(&mut self) {
        match self.parent.upgrade() {
            Some(parent) => {
                // Fail because parent is already borrowed to call this update                       
                if parent.try_borrow().unwrap().value == 0 {
                    // Do stuff
                }
            },
            None => Panic!("Parent was freed")
        }
        if some_condition {
            self.spawn_b();
        }
        for b in &self.b_lst {
            b.borrow_mut().update();
        }
    }

    // This infinite loop in this state, but it's for the example
    fn spawn_b(&mut self) {
        let b = Rc::new(RefCell::new(B::new()));
        b.borrow_mut().parent = self.parent.clone();
        if !self.end {
            b.borrow_mut().c_lst = vec![C::new(Rc::downgrade(&b)), C::new(Rc::downgrade(&b))];
            for c in b.borrow_mut().c {
                c.spawn_b();
            }
        }
        self.b_lst.push(b);
    }
}

As you see in the code, I can't access my parent state. Any suggestions?


Solution

  • The Rc/Weak tree in your example is a straightforward way to implement trees with parent references in Rust. The only issue is that your update function requires mutable access to the node its updating, which locks out the lower nodes from accessing the parent.

    You're going to have to make an architectural change to solve this. A couple ways of doing it: