Trying to do something like Cell::Ref, with safe code

Ref: Rust Playground

This is a set of types to implement single ownership with multiple weak pointers on top of safe Rc<RefCell>. OwnerCell owns T, via a Rc<RefCell>. OwnerCell is not cloneable, so it's single ownership. But you can get weak pointers from it. The weak references, if borrowed, do an upgrade and a borrow. Neither the borrow nor the upgrade can fail, because there's a check when OwnerCell is dropped for any outstanding borrows or weak references.

I modeled this after the way Cell::Ref works. But Cell::Ref uses a raw pointer to avoid problems with destruction order. So my example won't compile. Is it possible to do this entirely in safe Rust?

Your OwnerCellRef is self-referencial. There's probably no way without unsafe; your own or some crate's.

Hm.

The key concept here is that when you do a borrow, the thing you get has both the reference you want and something which, when dropped, undoes the borrow. That's hard to set up. But is it impossible in safe code?

Technically not impossible but the result is so useless that "impossible in safe code" is the practical answer. Borrowing forever is incompatible with destructors,[1] for example.

(And for that particular example, since it took an extra step to "activate" anyway, might as well return just something wrapping the Ref<'_, T>.)


  1. modulo an unstable impl Drop feature... which requires unsafe â†Šī¸Ž

1 Like

OK, no easy fix yet.

Going back to the original goal:

The idea here is to simplify the common case that comes up most of the time when you need a backlink. If you write this out with Rc, Weak, borrow(), and upgrade(), it's verbose and can fail if upgrade() returns None. The goals here are 1) to simplify this case, and 2) to push potential failures back to the point where the OwnerCell gets dropped. Upgrades can't fail, because weak and upgraded links can't outlive the Owner Cell, because dropping an OwnerCell with other references outstanding causes a panic.

For demo purposes, I'd like to implement this from well-known safe primitives, and not write unsafe code myself. That's why I built this on top of Rc, etc. Suggestions?