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 (T
implementsUnpin
. I’ll ignoreUnpin T
for 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 T
is slightly too powerful to guarantee that an object cannot be moved:&mut T
allows 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 T
where 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 whilePin<T>
exists. The second is when aPin<T>
is promoted into a&mut T
(Pin::get_unchecked_mut()
), giving it all the required power to misbehave with e.g.mem::replace
ormem::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 forPin<T>
, even for!Unpin T
. The rationale for this is that it is always safe to call the existingPin::new_unchecked(&mut T)
function, because rules of aliasing ensure we only have that one&mut T
to accessT
at this point, that&mut T
is borrowed by the function for the entire duration of thePin<&mut T>
, and in that function we are obviously not moving out ofT
. 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 byPin
? - 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?