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 (TimplementsUnpin. I’ll ignoreUnpin 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 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::replaceormem::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 Tto accessTat this point, that&mut Tis 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?