Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite pin module documentation to clarify usage and invariants #116129

Merged
merged 34 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
bfd63b2
Rewrite `Pin<P>` docs to clarify guarantees and uses
mcy Aug 30, 2021
8241ca6
mostly done
fu5ha Sep 25, 2023
ba3b934
Fix examples, finish polishing
fu5ha Sep 25, 2023
584f098
fix broken links
fu5ha Sep 25, 2023
ec8a01a
fix one more broken link
fu5ha Sep 25, 2023
46f9d77
update doubly linked list commentary and fix links
fu5ha Sep 25, 2023
db5b19e
improve intro and `Unpin`-related discussion
fu5ha Sep 26, 2023
6818d92
improve intro and discussion of pinning as library contract
fu5ha Sep 26, 2023
bebbe24
improve `Pin` struct docs and add examples
fu5ha Sep 26, 2023
82a6817
fix link in footnote
fu5ha Sep 27, 2023
e2e8746
reword unpin auto impl section
fu5ha Sep 27, 2023
7c9c712
improve structural Unpin + formatting
fu5ha Sep 27, 2023
252a83b
add section on manual owning ptr managed solution via @kpreid
fu5ha Sep 28, 2023
f2447a6
fix typos
fu5ha Sep 28, 2023
921d37d
fix imports
fu5ha Sep 28, 2023
6d5f43d
edit new section for typos and better wording
fu5ha Sep 28, 2023
de2e748
fix typos and edit prose
fu5ha Sep 28, 2023
6e88279
`Pin<P>` -> `Pin<Ptr>`
fu5ha Oct 3, 2023
469c78b
improve `Pin` and `Pin::new` docs
fu5ha Oct 3, 2023
e0210e6
justify motivation of `Unpin` better
fu5ha Oct 3, 2023
f0827b3
fix broken link
fu5ha Oct 3, 2023
d7a886a
update ui tests
fu5ha Oct 3, 2023
9997114
improve `Pin::new_unchecked` docs
fu5ha Oct 3, 2023
058fb50
trim section on managed-box model
fu5ha Oct 3, 2023
0050676
Rephrase unpin docs in terms of pinning-agnosticness
Manishearth Jan 7, 2024
936ceb2
lifetime -> lifespan where relevant. improve docs on as_ref()
Manishearth Jan 7, 2024
4c25246
Clean up guarantees wording
Manishearth Jan 7, 2024
68bdedd
Apply suggestions from code review
Manishearth Jan 7, 2024
6553d0d
punctuation in parens
Manishearth Jan 7, 2024
6a54ed7
valid
Manishearth Jan 7, 2024
a573c7c
footnote on dropping futures
Manishearth Jan 7, 2024
b1830f1
clean up structural pinning
Manishearth Jan 7, 2024
df6d449
Update library/core/src/pin.rs
Manishearth Jan 7, 2024
7fd841c
link
Manishearth Jan 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 47 additions & 24 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,25 +899,37 @@ marker_impls! {
{T: ?Sized} &mut T,
}

/// Types that can be safely moved after being pinned.
///
/// Rust itself has no notion of immovable types, and considers moves (e.g.,
/// through assignment or [`mem::replace`]) to always be safe.
///
/// The [`Pin`][Pin] type is used instead to prevent moves through the type
/// system. Pointers `P<T>` wrapped in the [`Pin<P<T>>`][Pin] wrapper can't be
/// moved out of. See the [`pin` module] documentation for more information on
/// pinning.
///
/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off
/// the type, which then allows moving `T` out of [`Pin<P<T>>`][Pin] with
/// functions such as [`mem::replace`].
///
/// `Unpin` has no consequence at all for non-pinned data. In particular,
/// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not
/// just when `T: Unpin`). However, you cannot use [`mem::replace`] on data
/// wrapped inside a [`Pin<P<T>>`][Pin] because you cannot get the `&mut T` you
/// need for that, and *that* is what makes this system work.
/// Types that do not require any pinning guarantees.
///
/// For information on what "pinning" is, see the [`pin` module] documentation.
///
/// Implementing the `Unpin` trait for `T` expresses the fact that `T` is pinning-agnostic:
/// it shall not expose nor rely on any pinning guarantees. This, in turn, means that a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential concern: Unpin types are pinning agnostic in the sense that pinning makes no difference for them. That doesn't mean they don't expose nor rely on any pinning guarantees! For instance, we could define a type PinBox of a box that's always pinned, and we could mark that type Unpin, since Pin<PinBox<T>> and PinBox<T> make the same guarantees -- in both cases, the T is pinned.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems footnote worthy. That's a bit of a rabbithole for most people reading this, but I agree we should call it out. I'm not the best person to write copy for this.

/// `Pin`-wrapped pointer to such a type can feature a *fully unrestricted* API.
/// In other words, if `T: Unpin`, a value of type `T` will *not* be bound by the invariants
/// which pinning otherwise offers, even when "pinned" by a [`Pin<Ptr>`] pointing at it.
/// When a value of type `T` is pointed at by a [`Pin<Ptr>`], [`Pin`] will not restrict access
/// to the pointee value like it normally would, thus allowing the user to do anything that they
/// normally could with a non-[`Pin`]-wrapped `Ptr` to that value.
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
///
/// The idea of this trait is to alleviate the reduced ergonomics of APIs that require the use
/// of [`Pin`] for soundness for some types, but which also want to be used by other types that
/// don't care about pinning. The prime example of such an API is [`Future::poll`]. There are many
/// [`Future`] types that don't care about pinning. These futures can implement `Unpin` and
/// therefore get around the pinning related restrictions in the API, while still allowing the
/// subset of [`Future`]s which *do* require pinning to be implemented soundly.
///
/// For more discussion on the consequences of [`Unpin`] within the wider scope of the pinning
/// system, see the [section about `Unpin`] in the [`pin` module].
///
/// `Unpin` has no consequence at all for non-pinned data. In particular, [`mem::replace`] happily
/// moves `!Unpin` data, which would be immovable when pinned ([`mem::replace`] works for any
/// `&mut T`, not just when `T: Unpin`).
///
/// *However*, you cannot use [`mem::replace`] on `!Unpin` data which is *pinned* by being wrapped
/// inside a [`Pin<Ptr>`] pointing at it. This is because you cannot (safely) use a
/// [`Pin<Ptr>`] to get an `&mut T` to its pointee value, which you would need to call
/// [`mem::replace`], and *that* is what makes this system work.
///
/// So this, for example, can only be done on types implementing `Unpin`:
///
Expand All @@ -935,11 +947,22 @@ marker_impls! {
/// mem::replace(&mut *pinned_string, "other".to_string());
/// ```
///
/// This trait is automatically implemented for almost every type.
///
/// [`mem::replace`]: crate::mem::replace
/// [Pin]: crate::pin::Pin
/// [`pin` module]: crate::pin
/// This trait is automatically implemented for almost every type. The compiler is free
/// to take the conservative stance of marking types as [`Unpin`] so long as all of the types that
/// compose its fields are also [`Unpin`]. This is because if a type implements [`Unpin`], then it
/// is unsound for that type's implementation to rely on pinning-related guarantees for soundness,
/// *even* when viewed through a "pinning" pointer! It is the responsibility of the implementor of
/// a type that relies upon pinning for soundness to ensure that type is *not* marked as [`Unpin`]
/// by adding [`PhantomPinned`] field. For more details, see the [`pin` module] docs.
///
/// [`mem::replace`]: crate::mem::replace "mem replace"
/// [`Future`]: crate::future::Future "Future"
/// [`Future::poll`]: crate::future::Future::poll "Future poll"
/// [`Pin`]: crate::pin::Pin "Pin"
/// [`Pin<Ptr>`]: crate::pin::Pin "Pin"
/// [`pin` module]: crate::pin "pin module"
/// [section about `Unpin`]: crate::pin#unpin "pin module docs about unpin"
/// [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe"
#[stable(feature = "pin", since = "1.33.0")]
#[diagnostic::on_unimplemented(
note = "consider using the `pin!` macro\nconsider using `Box::pin` if you need to access the pinned value outside of the current scope",
Expand Down
Loading
Loading