about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2019-02-20 19:34:10 +0100
committerRalf Jung <post@ralfj.de>2019-02-20 19:38:28 +0100
commit1b556f16c9e6779610a8f64fe06f9947bc2cdbe8 (patch)
treebab4ec42d29b22405295be84f97244699aea8aa9
parent06b2affa7879e609bcef70d726f900d8430f6e0a (diff)
downloadrust-1b556f16c9e6779610a8f64fe06f9947bc2cdbe8.tar.gz
rust-1b556f16c9e6779610a8f64fe06f9947bc2cdbe8.zip
expand pinning projections
-rw-r--r--src/libcore/pin.rs79
1 files changed, 41 insertions, 38 deletions
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index 01d384f3e19..b238c56da66 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -182,46 +182,49 @@
 //! is entirely up to the author of any given type. For many types, both answers are reasonable
 //! (e.g., there could be a version of `Vec` with structural pinning and another
 //! version where the contents remain movable even when the `Vec` is pinned).
-//! If pinning is not structural, the wrapper can `impl<T> Unpin for Wrapper<T>`.
-//! If pinning is structural, the wrapper type can offer pinning projections.
+//! If the type should have pinning projections, pinning must be structural.
 //! However, structural pinning comes with a few extra requirements:
 //!
-//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are
-//!    `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
-//!    the wrapper it is your responsibility *not* to add something like
-//!    `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation
-//!    requires unsafe code, so the fact that `Unpin` is a safe trait  does not break
-//!    the principle that you only have to worry about any of this if you use `unsafe`.)
-//! 2. The destructor of the wrapper must not move out of its argument. This is the exact
-//!    point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`,
-//!    but the wrapper (and hence its fields) might have been pinned before.
-//!    You have to guarantee that you do not move a field inside your `Drop` implementation.
-//!    In particular, as explained previously, this means that your wrapper type must *not*
-//!    be `#[repr(packed)]`.
-//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]:
-//!    once your wrapper is pinned, the memory that contains the
-//!    content is not overwritten or deallocated without calling the content's destructors.
-//!    This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail
-//!    to call `drop` on all elements if one of the destructors panics. This violates the
-//!    `Drop` guarantee, because it can lead to elements being deallocated without
-//!    their destructor being called. (`VecDeque` has no pinning projections, so this
-//!    does not cause unsoundness.)
-//! 4. You must not offer any other operations that could lead to data being moved out of
-//!    the fields when your type is pinned. This is usually not a concern, but can become
-//!    tricky when interior mutability is involved. For example, imagine if `RefCell`
-//!    had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`.
-//!    Then we could do the following:
-//!    ```compile_fail
-//!    fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>) {
-//!        { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T`
-//!        let rc_shr: &RefCell<T> = rc.into_ref().get_ref();
-//!        let b = rc_shr.borrow_mut();
-//!        let content = &mut *b; // and here we have `&mut T` to the same data
-//!    }
-//!    ```
-//!    This is catastrophic, it means we can first pin the content of the `RefCell`
-//!    (using `RefCell::get_pin_mut`) and then move that content using the mutable
-//!    reference we got later.
+//! 1.  The wrapper must only be [`Unpin`] if all the fields one can project to are
+//!     `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
+//!     the wrapper it is your responsibility *not* to add something like
+//!     `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation
+//!     requires unsafe code, so the fact that `Unpin` is a safe trait  does not break
+//!     the principle that you only have to worry about any of this if you use `unsafe`.)
+//! 2.  The destructor of the wrapper must not move out of its argument. This is the exact
+//!     point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`,
+//!      but the wrapper (and hence its fields) might have been pinned before.
+//!     You have to guarantee that you do not move a field inside your `Drop` implementation.
+//!     In particular, as explained previously, this means that your wrapper type must *not*
+//!     be `#[repr(packed)]`.
+//! 3.  You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]:
+//!     once your wrapper is pinned, the memory that contains the
+//!     content is not overwritten or deallocated without calling the content's destructors.
+//!     This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail
+//!     to call `drop` on all elements if one of the destructors panics. This violates the
+//!     `Drop` guarantee, because it can lead to elements being deallocated without
+//!     their destructor being called. (`VecDeque` has no pinning projections, so this
+//!     does not cause unsoundness.)
+//! 4.  You must not offer any other operations that could lead to data being moved out of
+//!     the fields when your type is pinned. For example, if the wrapper contains an
+//!     `Option<T>` and there is an operation such as `fn(Pin<&mut Wrapper<T>>) -> Option<T>`,
+//!     that operation can be used to move a `T` out of a pinned `Wrapper` -- that means
+//!     pinning cannot be structural.
+//!
+//!     For a more complex example of moving data out of a pinnd type, imagine if `RefCell`
+//!     had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`.
+//!     Then we could do the following:
+//!     ```compile_fail
+//!     fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>) {
+//!         { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T`
+//!         let rc_shr: &RefCell<T> = rc.into_ref().get_ref();
+//!         let b = rc_shr.borrow_mut();
+//!         let content = &mut *b; // and here we have `&mut T` to the same data
+//!     }
+//!     ```
+//!     This is catastrophic, it means we can first pin the content of the `RefCell`
+//!     (using `RefCell::get_pin_mut`) and then move that content using the mutable
+//!     reference we got later.
 //!
 //! On the other hand, if you decide *not* to offer any pinning projections, you
 //! do not have to do anything. If your type also does not do any pinning itself,