BorrowMutError when called inside Drop trait

I have the following structure.

pub struct Window {
  sub_windows: Vec<WindowRef>,
  parent: Option<WindowRef>,
  id: usize
}

type WinRef = Rc<RefCell<Window>>;
pub struct WindowRef(WinRef);

I am able to do the following and it works as expected with no BorrowMutError

impl WindowRef {
  pub fn inner_mut(&mut self) -> RefMut<'_, Window> {
    self.0.borrow_mut()
  }

  pub fn delete(&mut self) {
    let id = self.id();
    match self.parent() {
      Some(mut p) => p.inner_mut().delete_child_by_id(id),
      None => ()
    }
  }
}

But it shows already borrowed: BorrowMutError when I move the same exact code inside drop

impl Drop for WindowRef {
  fn drop(&mut self) {
    let id = self.id();
    match self.parent() {
      Some(mut p) => p.inner_mut().delete_child_by_id(id),
      None => ()
    }
  }
}

Am I missing something?

The p.inner_mut().delete_child_by_id(id) will be removing the entry from the parent’s sub_windows: Vec<WindowRef> field, which will cause the same kind of drop code to be executed another time (while the outer drop call is still holding onto the borrow_mut of the parent.

It seems generally questionable to implicitly “delete” the window’s entry with its parent any time any WindowRef gets dropped, I mean, dropping a Window would cause the window’s parent, and thus also its grandparents and siblings, and so on… to be “deleted”. Well… it might make sense actually, in case you ensure that only a single WindowRef (perhaps with a better type name) gets handed out to user code… in any case, using this same drop==delete-the-target kind of WindowRef type internally in the Window structure, too, is probably a mistake. If your goal here is to be able to - recursively - drop an entire window tree despite of the reference cycles, a different approach might be better… e.g. you could use some explicit loop or recursive function; or you could use Weak references for the back-pointer to the parent (which might, depending on the use-case, even allow to skip the Option and use the Weak pointers own Option-like properties).

1 Like