Let's assume it exists with types Strong<T>
and Weak<T>
. How do you use Weak<T>
? You need some kind of fallible "upgrade" step, so what does Weak<T>
upgrade to? It can't be to a plain reference (as you've stated), because Strong<T>
needs to know whether or not any "upgraded" Weak<T>
s exist. If it didn't, it could deallocate its storage whilst the value is still being accessed.
So Weak<T>
must upgrade to some kind of SemiWeak<T>
which keeps the underlying allocation alive... which is exactly what shared ownership is.
What if you somehow guaranteed that Strong<T>
couldn't be deallocated before all Weak<T>
s go away? Congratulations, you've just re-invented T
and &T
: you could literally just use those instead.
Alright, so what if you made it so that Weak<T>
upgrades into a SemiWeak<'a, T>
that is tied to the lifetime of the Weak<T>
so that it can't outlive it, and can only be a temporary? All you're really doing in that case is hiding the fact that you've got shared ownership. Under the hood, SemiWeak
would still need to guarantee the underlying Strong
can't go away. You could trivially build such a type from Rc<T>
in perhaps ten minutes. This would effectively give you a type that is exactly like Rc<T>
, with the same performance and memory cost, but less useful.
In addition, that get_mut
method can't exist. There's no way to prevent SemiWeak<T>
s from existing. Unless you use borrowing but, again, that's just using T
and &T
.
So, no, I don't think this exists, nor do I believe it can in the form you've described.
As a final aside, just having Weak<T>
at all is a form of shared ownership, because those Weak<T>
s need to point to something. In the case of Rc<T>
, the weak counter is stored right alongside the strong counter, so whilst the value can be destroyed, the allocation itself sticks around. You could split the two, but now you're paying for two allocations and double indirection (probably leading to more cache misses).