-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Description
Currently, you cannot even construct a Pin
unless the pointer it wraps implements Deref
. This means you cannot have a Pin<*const T>
, Pin<*mut T>
or Pin<NonNull<T>>
. We should consider extending the API of Pin to support these constructs.
Unfortunately, I don't know if there's much this actually helps, because we have no unsafe equivalent of Deref
as a trait abstraction. As a result, I think the only APIs that could apply to these pointers generically is:
unsafe fn new_unchecked(p: P) -> Pin<P>
unsafe fn into_inner(self: Pin<P>) -> P
This limits the utility of Pin
on these pointers, since it basically guarantees nothing with this API.
If we had an UnsafeAsRef
trait, we could support unsafe equivalents of as_ref
and as_mut
, allowing you to at least maintain the pinning invariant in your unsafe code. In other words, some sort of UnsafeAsRef
and UnsafeAsMut
traits would be necessary for this to actually be helpful. I'm not sure if those traits are worth adding.
Activity
withoutboats commentedon Oct 4, 2018
cc @cramertj @RalfJung
withoutboats commentedon Oct 4, 2018
I have a pointer right now which is supposed to be sematically a
Pin<NonNull<T>>
:In practice what I do is this:
Pin<&T>
, these APIs are safe.NonNull<T>
, and convert it to aPin<&T>
when I call those APIs.This means the pinning invariant could be broken anywhere in my code that can see the
NonNull<T>
. If I could store it as aPin<NonNull<T>>
, that code would only be responsible for making sure it never calls those safe APIs with a dangling pointer.(FWIW the pinning invariant is important in this code because
T
contains an intrusive doubly linked list, rather than self-referential structures.)RalfJung commentedon Oct 5, 2018
An alternative might be to have a dedicated trait just for
Pin
. I'd prefer that anyway to make sure people explicitly opt-in to pinning support with their types. Would that help?paxbun commentedon Apr 13, 2024
We also need this feature. We have many types that are elements of a huge graph (or a tree). To avoid excessive use of RC smart pointers, the children of each node are stored in a type wrapping a vector, which ensures that the elements are pinned and cannot be moved (The iterator of that type also returns Pin<&mut T>), and We're using NonNull internally to represent cross edges or parents.
Using NonNull so means that the pointee is also pinned, and they're also exposed as &T or Pin<&mut T>. This kind of code needs a lot of conversions from NonNull to Pin<&mut T> or vice versa, but Pin<&mut T> to NonNull conversion results in verbose code.