mention interaction with Deref in intro

This commit is contained in:
Ralf Jung 2019-02-19 21:12:48 +01:00
parent c774bc650a
commit c8f4efc006

View file

@ -19,6 +19,7 @@
//! obtain a `Box` or reference to pinned data, which implies that you cannot use
//! operations such as [`mem::swap`]:
//! ```
//! use std::pin::Pin;
//! fn swap_pins<T>(x: Pin<&mut T>, y: Pin<&mut T>) {
//! // `mem::swap` needs `&mut T`, but we cannot get it.
//! // We are stuck, we cannot swap the contents of these references.
@ -32,6 +33,15 @@
//! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being
//! moved by making it impossible to call methods like [`mem::swap`] on them.
//!
//! [`Pin`] can be used to wrap any pointer type, and as such it interacts with
//! [`Deref`] and [`DerefMut`]. A `Pin<P>` where `P: Deref` should be considered
//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin<Box<T>>` is
//! an owned pointer to a pinned `T`, and a `Pin<Rc<T>>` is a reference-counted
//! pointer to a pinned `T`.
//! For correctness, [`Pin`] relies on the [`Deref`] and [`DerefMut`] implementations
//! to not move out of their `self` parameter, and to only ever return a pointer
//! to pinned data when they are called on a pinned pointer.
//!
//! # `Unpin`
//!
//! However, these restrictions are usually not necessary. Many types are always freely
@ -114,7 +124,7 @@
//! list element will patch the pointers of its predecessor and successor to remove itself
//! from the list.
//!
//! To make this work, it is crucial taht we can actually rely on `drop` being called.
//! To make this work, it is crucial that we can actually rely on `drop` being called.
//! And, in fact, this is a guarantee that `Pin` provides.
//!
//! # `Drop` guarantee
@ -219,6 +229,8 @@
//!
//! [`Pin`]: struct.Pin.html
//! [`Unpin`]: ../../std/marker/trait.Unpin.html
//! [`Deref`]: ../../std/ops/trait.Deref.html
//! [`DerefMut`]: ../../std/ops/trait.DerefMut.html
//! [`mem::swap`]: ../../std/mem/fn.swap.html
//! [`mem::forget`]: ../../std/mem/fn.forget.html
//! [`Box`]: ../../std/boxed/struct.Box.html
@ -319,16 +331,16 @@ impl<P: Deref> Pin<P> {
/// Construct a new `Pin` around a reference to some data of a type that
/// may or may not implement `Unpin`.
///
/// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
/// instead.
///
/// # Safety
///
/// This constructor is unsafe because we cannot guarantee that the data
/// pointed to by `pointer` is pinned, meaning that the data will not be moved or
/// its storage invalidated until it gets dropped. If the constructed `Pin<P>` does
/// not guarantee that the data `P` points to is pinned, constructing a
/// `Pin<P>` is unsafe. In particular, calling `Pin::new_unchecked`
/// on an `&'a mut T` is unsafe because while you are able to pin it for the given
/// lifetime `'a`, you have no control over whether it is kept pinned once `'a`
/// ends. A value, once pinned, must remain pinned forever (unless its type implements `Unpin`).
/// `Pin<P>` is unsafe. In particular,
///
/// By using this method, you are making a promise about the `P::Deref` and
/// `P::DerefMut` implementations, if they exist. Most importantly, they
@ -340,21 +352,38 @@ impl<P: Deref> Pin<P> {
/// must not be possible to obtain a `&mut P::Target` and then
/// move out of that reference (using, for example [`mem::swap`]).
///
/// For example, the following is a *violation* of `Pin`'s safety:
/// For example, calling `Pin::new_unchecked`
/// on an `&'a mut T` is unsafe because while you are able to pin it for the given
/// lifetime `'a`, you have no control over whether it is kept pinned once `'a` ends:
/// ```
/// use std::mem;
/// use std::pin::Pin;
///
/// fn foo<T>(mut a: T, mut b: T) {
/// fn move_pinned_ref<T>(mut a: T, mut b: T) {
/// unsafe { let p = Pin::new_unchecked(&mut a); } // should mean `a` can never move again
/// mem::swap(&mut a, &mut b);
/// // the address of `a` changed to `b`'s stack slot, so `a` got moved even
/// // though we have previously pinned it!
/// }
/// ```
/// A value, once pinned, must remain pinned forever (unless its type implements `Unpin`).
///
/// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
/// instead.
/// Similarily, calling `Pin::new_unchecked` on a `Rc<T>` is unsafe because there could be
/// aliases to the same data that are not subject to the pinning restrictions:
/// ```
/// use std::rc::Rc;
/// use std::pin::Pin;
///
/// fn move_pinned_rc<T>(mut x: Rc<T>) {
/// let pinned = unsafe { Pin::new_unchecked(x.clone()) };
/// { let p: Pin<&T> = pinned.as_ref(); } // should mean the pointee can never move again
/// drop(pinned);
/// let content = Rc::get_mut(&mut x).unwrap();
/// // Now, if `x` was the only reference, we have a mutable reference to
/// // data that we pinned above, which we could use to move it as we have
/// // seen in the previous example.
/// }
/// ```
///
/// [`mem::swap`]: ../../std/mem/fn.swap.html
#[stable(feature = "pin", since = "1.33.0")]