Downgrade a Pin<Rc<T>>

I'm working with Pin<Rc<SomeNotUnpinType>>, and I'd like to produce a weak pointer to the underlying allocation. I can imagine two signatures here:

  • Pin<Rc<T>> -> Pin<rc::Weak<T>>: a pinned weak pointer is not super useful since Weak<T> is not Deref, but this still has the effect of keeping the backing allocation alive, and it seems like this form of downgrade should be sound
  • Pin<Rc<T>> -> rc::Weak<T>: I am less sure that this can be done soundly, seems like it might be possible to exploit it to break the Pin invariant by upgrading the Weak, but if it were possible to implement soundly this would be the more useful conversion

So, can either of these downgrades be written soundly? If so, how?

Can you clone() the inner Rc and then downgrade that?

Edit. No, you can't, because Pin doesn't give you any access to the pointer type by default.

Which is a good thing in hindsight, because any route that potentially gives you an unpinned Rc<T> will then let you move the value via Rc::try_unwrap, which breaks the Pin guarantee. So, the best you can hope for is something that will give you Pin<Weak<T>>.

1 Like

The first version is fine, but you probably need to do it unsafely.

2 Likes

Thanks! Would you expect the complementary upgrade operation Pin<Weak<T>> -> Option<Pin<Rc<T>>> to also be okay?

I see no problem with that.

2 Likes

I don’t think there’s any way of constructing Pin<Weak<T>> as even new_unchecked requires P: Deref, no?

In terms of usable, existing alternatives, there exists https://crates.io/crates/pin-weak

2 Likes

Yeah, I was stymied trying to come up with ways to implement the downgrade even in unsafe code. Perhaps transmute could do it.

Thanks for the pointer to the pin-weak crate!

Ah, well, that could work - but that seems unnecessarily unsafe.

Also at that point, arguably, you’d be inventing a meaning (and safety invariants) of Pin<Weak<T>> that may be incompatible (i.e. unsound when combined) with the ones other library authors may come up with, so it seems advisable to avoid doing so and to use a custom type instead, as the pin-weak crate does, too :slight_smile:

Yeah, if the Pin<Weak<T>> were going to be part of my public API this would be a major concern. In practice I just need "something that acts like a weak pointer to pinned data" for internal use, which the crate seems to provide -- I may just open-code the relevant parts of that implementation.

You can make a PinWeak<T> struct that wraps a Weak<T> and provides conversion to/from Pin<Arc<T>>.

1 Like