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

Expand std::pin module docs and rename std::pin::Pinned to PhantomPinned #55992

Merged
merged 2 commits into from
Dec 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,15 +640,15 @@ unsafe impl<T: ?Sized> Freeze for &mut T {}
#[unstable(feature = "pin", issue = "49150")]
pub auto trait Unpin {}

/// A type which does not implement `Unpin`.
/// A marker type which does not implement `Unpin`.
///
/// If a type contains a `Pinned`, it will not implement `Unpin` by default.
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
#[unstable(feature = "pin", issue = "49150")]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Pinned;
pub struct PhantomPinned;

#[unstable(feature = "pin", issue = "49150")]
impl !Unpin for Pinned {}
impl !Unpin for PhantomPinned {}

#[unstable(feature = "pin", issue = "49150")]
impl<'a, T: ?Sized + 'a> Unpin for &'a T {}
Expand Down
46 changes: 28 additions & 18 deletions src/libcore/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,33 @@
//! since moving an object with pointers to itself will invalidate them,
//! which could cause undefined behavior.
//!
//! In order to prevent objects from moving, they must be pinned
//! by wrapping a pointer to the data in the [`Pin`] type. A pointer wrapped
//! in a `Pin` is otherwise equivalent to its normal version, e.g., `Pin<Box<T>>`
//! and `Box<T>` work the same way except that the first is pinning the value
//! of `T` in place.
//! By default, all types in Rust are movable. Rust allows passing all types by-value,
//! and common smart-pointer types such as `Box`, `Rc`, and `&mut` allow replacing and
cramertj marked this conversation as resolved.
Show resolved Hide resolved
//! moving the values they contain. In order to prevent objects from moving, they must
//! be pinned by wrapping a pointer to the data in the [`Pin`] type.
//! Doing this prohibits moving the value behind the pointer.
//! For example, `Pin<Box<T>>` functions much like a regular `Box<T>`,
//! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved,
//! but the value behind it cannot.
//!
//! First of all, these are pointer types because pinned data mustn't be passed around by value
//! (that would change its location in memory).
//! Secondly, since data can be moved out of `&mut` and `Box` with functions such as [`swap`],
//! which causes their contents to swap places in memory,
//! we need dedicated types that prohibit such operations.
//! Since data can be moved out of `&mut` and `Box` with functions such as [`swap`],
//! changing the location of the underlying data, [`Pin`] prohibits accessing the
//! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of
//! APIs for accessing and using the value. [`Pin`] also guarantees that no other
//! functions will move the pointed-to value. This allows for the creation of
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we may want to say "no later code", or something along those lines, instead of "other functions". The contract around Pin talks about what cannot happen "in the future", but the current text doesn't currently say that.

//! self-references and other special behaviors that are only possible for unmovable
//! values.
//!
//! However, these restrictions are usually not necessary,
//! so most types implement the [`Unpin`] auto-trait,
//! which indicates that the type can be moved out safely.
//! Doing so removes the limitations of pinning types,
//! making them the same as their non-pinning counterparts.
//! However, these restrictions are usually not necessary. Many types are always freely
//! movable. These types implement the [`Unpin`] auto-trait, which nullifies the affect
//! of [`Pin`]. For `T: Unpin`, `Pin<Box<T>>` and `Box<T>` function identically, as do
//! `Pin<&mut T>` and `&mut T`.
//!
//! Note that pinning and `Unpin` only affect the pointed-to type. For example, whether
//! or not `Box<T>` is `Unpin` has no affect on the behavior of `Pin<Box<T>>`. Similarly,
//! `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves, even though the
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be Box<T> and &mut T? We have an impl Unpin for Box<T> where T: !Unpin, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Those are also Unpin, but I was specifically referring to the Pin-wrapped types to clarify that Pin does not make something !Unpin.

//! `T` underneath them isn't, because the pointers in `Pin<Box<_>>` and `Pin<&mut _>`
//! are always freely movable, even if the data they point to isn't.
//!
//! [`Pin`]: struct.Pin.html
//! [`Unpin`]: trait.Unpin.html
Expand All @@ -36,7 +46,7 @@
//! #![feature(pin)]
//!
//! use std::pin::Pin;
//! use std::marker::Pinned;
//! use std::marker::PhantomPinned;
//! use std::ptr::NonNull;
//!
//! // This is a self-referential struct since the slice field points to the data field.
Expand All @@ -47,7 +57,7 @@
//! struct Unmovable {
//! data: String,
//! slice: NonNull<String>,
//! _pin: Pinned,
//! _pin: PhantomPinned,
//! }
//!
//! impl Unmovable {
Expand All @@ -60,7 +70,7 @@
//! // we only create the pointer once the data is in place
//! // otherwise it will have already moved before we even started
//! slice: NonNull::dangling(),
//! _pin: Pinned,
//! _pin: PhantomPinned,
//! };
//! let mut boxed = Box::pinned(res);
//!
Expand Down