Skip to content

Commit 35d00bf

Browse files
authored
Unrolled build for rust-lang#116129
Rollup merge of rust-lang#116129 - fu5ha:better-pin-docs-2, r=Amanieu Rewrite `pin` module documentation to clarify usage and invariants The documentation of `pin` today does not give a complete treatment of pinning from first principles, nor does it adequately help build intuition and understanding for how the different elements of the pinning story fit together. This rewrite attempts to address these in a way that makes the concept more approachable while also making the documentation more normative. This PR picks up where `@mcy` left off in rust-lang#88500 (thanks to him for the original work and `@Manishearth` for mentioning it such that I originally found it). I've directly incorporated much of the feedback left on the original PR and have rewritten and changed some of the main conceits of the prose to better adhere to the feedback from the reviewers on that PR or just explain something in (hopefully) a better way.
2 parents 75c68cf + 7fd841c commit 35d00bf

6 files changed

+1104
-375
lines changed

library/core/src/marker.rs

+47-24
Original file line numberDiff line numberDiff line change
@@ -899,25 +899,37 @@ marker_impls! {
899899
{T: ?Sized} &mut T,
900900
}
901901

902-
/// Types that can be safely moved after being pinned.
903-
///
904-
/// Rust itself has no notion of immovable types, and considers moves (e.g.,
905-
/// through assignment or [`mem::replace`]) to always be safe.
906-
///
907-
/// The [`Pin`][Pin] type is used instead to prevent moves through the type
908-
/// system. Pointers `P<T>` wrapped in the [`Pin<P<T>>`][Pin] wrapper can't be
909-
/// moved out of. See the [`pin` module] documentation for more information on
910-
/// pinning.
911-
///
912-
/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off
913-
/// the type, which then allows moving `T` out of [`Pin<P<T>>`][Pin] with
914-
/// functions such as [`mem::replace`].
915-
///
916-
/// `Unpin` has no consequence at all for non-pinned data. In particular,
917-
/// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not
918-
/// just when `T: Unpin`). However, you cannot use [`mem::replace`] on data
919-
/// wrapped inside a [`Pin<P<T>>`][Pin] because you cannot get the `&mut T` you
920-
/// need for that, and *that* is what makes this system work.
902+
/// Types that do not require any pinning guarantees.
903+
///
904+
/// For information on what "pinning" is, see the [`pin` module] documentation.
905+
///
906+
/// Implementing the `Unpin` trait for `T` expresses the fact that `T` is pinning-agnostic:
907+
/// it shall not expose nor rely on any pinning guarantees. This, in turn, means that a
908+
/// `Pin`-wrapped pointer to such a type can feature a *fully unrestricted* API.
909+
/// In other words, if `T: Unpin`, a value of type `T` will *not* be bound by the invariants
910+
/// which pinning otherwise offers, even when "pinned" by a [`Pin<Ptr>`] pointing at it.
911+
/// When a value of type `T` is pointed at by a [`Pin<Ptr>`], [`Pin`] will not restrict access
912+
/// to the pointee value like it normally would, thus allowing the user to do anything that they
913+
/// normally could with a non-[`Pin`]-wrapped `Ptr` to that value.
914+
///
915+
/// The idea of this trait is to alleviate the reduced ergonomics of APIs that require the use
916+
/// of [`Pin`] for soundness for some types, but which also want to be used by other types that
917+
/// don't care about pinning. The prime example of such an API is [`Future::poll`]. There are many
918+
/// [`Future`] types that don't care about pinning. These futures can implement `Unpin` and
919+
/// therefore get around the pinning related restrictions in the API, while still allowing the
920+
/// subset of [`Future`]s which *do* require pinning to be implemented soundly.
921+
///
922+
/// For more discussion on the consequences of [`Unpin`] within the wider scope of the pinning
923+
/// system, see the [section about `Unpin`] in the [`pin` module].
924+
///
925+
/// `Unpin` has no consequence at all for non-pinned data. In particular, [`mem::replace`] happily
926+
/// moves `!Unpin` data, which would be immovable when pinned ([`mem::replace`] works for any
927+
/// `&mut T`, not just when `T: Unpin`).
928+
///
929+
/// *However*, you cannot use [`mem::replace`] on `!Unpin` data which is *pinned* by being wrapped
930+
/// inside a [`Pin<Ptr>`] pointing at it. This is because you cannot (safely) use a
931+
/// [`Pin<Ptr>`] to get an `&mut T` to its pointee value, which you would need to call
932+
/// [`mem::replace`], and *that* is what makes this system work.
921933
///
922934
/// So this, for example, can only be done on types implementing `Unpin`:
923935
///
@@ -935,11 +947,22 @@ marker_impls! {
935947
/// mem::replace(&mut *pinned_string, "other".to_string());
936948
/// ```
937949
///
938-
/// This trait is automatically implemented for almost every type.
939-
///
940-
/// [`mem::replace`]: crate::mem::replace
941-
/// [Pin]: crate::pin::Pin
942-
/// [`pin` module]: crate::pin
950+
/// This trait is automatically implemented for almost every type. The compiler is free
951+
/// to take the conservative stance of marking types as [`Unpin`] so long as all of the types that
952+
/// compose its fields are also [`Unpin`]. This is because if a type implements [`Unpin`], then it
953+
/// is unsound for that type's implementation to rely on pinning-related guarantees for soundness,
954+
/// *even* when viewed through a "pinning" pointer! It is the responsibility of the implementor of
955+
/// a type that relies upon pinning for soundness to ensure that type is *not* marked as [`Unpin`]
956+
/// by adding [`PhantomPinned`] field. For more details, see the [`pin` module] docs.
957+
///
958+
/// [`mem::replace`]: crate::mem::replace "mem replace"
959+
/// [`Future`]: crate::future::Future "Future"
960+
/// [`Future::poll`]: crate::future::Future::poll "Future poll"
961+
/// [`Pin`]: crate::pin::Pin "Pin"
962+
/// [`Pin<Ptr>`]: crate::pin::Pin "Pin"
963+
/// [`pin` module]: crate::pin "pin module"
964+
/// [section about `Unpin`]: crate::pin#unpin "pin module docs about unpin"
965+
/// [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe"
943966
#[stable(feature = "pin", since = "1.33.0")]
944967
#[diagnostic::on_unimplemented(
945968
note = "consider using the `pin!` macro\nconsider using `Box::pin` if you need to access the pinned value outside of the current scope",

0 commit comments

Comments
 (0)