So I’ve been testing
Pin on beta, and I’ve got some questions.
From my comprehension when reading the doc, a
Pin<T>is a pointer type that offers the guarantee that its pointed value will not move as long as the Pin exists, unless “it doesn’t matter” that the pointed value moves (
Unpin. I’ll ignore
Unpin Tfor the rest of this message). Cases where it does matter are typically self-referential structs that are in a way observing their own address.
Pin<T>comes basically as a solution to the fact that
&mut Tis slightly too powerful to guarantee that an object cannot be moved:
&mut Tallows to swap the data of two references, possibly changing their address, hence resulting on a “move” of the pointed-to objects.
Pin<T>aims to “behave like
&mut Twhere possible”, and to restrict its powers to hold its guarantee. Is that clunky explanation correct?
Still in my comprehension,
Pin<T>has two critical “unsafe points” in its usage: the first is when it is created from a pointer (
Pin::new_unchecked), where the caller must ensure that the pointed-to object is in fact “pinned”, ie won’t be moved while
Pin<T>exists. The second is when a
Pin<T>is promoted into a
Pin::get_unchecked_mut()), giving it all the required power to misbehave with e.g.
mem::swap. The safety of that second point relies on the caller promising not to misuse the obtained
&mut T. Is this explanation still correct?
If 1. and 2. hold, then I believe we could add a safe
Pin::new(&mut T) -> Pin<&mut T>safe constructor for
Pin<T>, even for
!Unpin T. The rationale for this is that it is always safe to call the existing
Pin::new_unchecked(&mut T)function, because rules of aliasing ensure we only have that one
&mut Tto access
Tat this point, that
&mut Tis borrowed by the function for the entire duration of the
Pin<&mut T>, and in that function we are obviously not moving out of
T. See a code example in Playground. To my knowledge there is no such function. So what am I missing?
- Is that function somehow available and I missed it? I skimmed the doc for Pin and &mut ref, but there are many impl block with various bounds so maybe I just missed something?
- Am I misunderstanding something about
Pin<T>that makes my proposed constructor unsound with regards to the guarantees provided by
- Any other reason for that function to be missing?
Otherwise, I find the
Pin API to be a great step forward regarding unmovable/autoreferential structs, if only a bit hard to understand, wrt its guarantees.
Bonus question: If my understanding is correct, the example in the pin module documentation is unsound just if we remove the
PhantomPinned member. While OK because of its use of
unsafe, I find a bit dangerous that we have no way to mark autoreferential structs as
!Unpin automatically. Would there be a way to do this?