diff options
| author | Ralf Jung <post@ralfj.de> | 2019-02-21 10:21:59 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2019-02-21 10:21:59 +0100 |
| commit | 59bdb31c890adf726aec2036c3c8170c2e3a1767 (patch) | |
| tree | 303222e8eba7936f0a55364d07763a6729bb0f27 | |
| parent | c9ade6a577ae92d951aecd95973fefb69cdbf08a (diff) | |
| download | rust-59bdb31c890adf726aec2036c3c8170c2e3a1767.tar.gz rust-59bdb31c890adf726aec2036c3c8170c2e3a1767.zip | |
final pin projections tweaking
| -rw-r--r-- | src/libcore/pin.rs | 50 |
1 files changed, 23 insertions, 27 deletions
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 4245c9dcd99..bcd5c65d381 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -177,20 +177,12 @@ //! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`) //! have an operation with type `fn(Pin<&[mut] Wrapper<T>>) -> Pin<&[mut] T>`? //! -//! This question is closely related to the question of whether pinning is "structural". -//! Structural pinning means that when you have pinned a wrapper type, the contents are -//! also pinned. Structural pinning thus explains why pinning projections are correct. This means -//! that if the type should have pinning projections for some fields, pinning must be structural -//! for those fields. +//! Having a pinning projection for some field means that pinning is "structural": +//! when the wrapper is pinned, the field must be considered pinned, too. +//! After all, the pinning projection lets us get a `Pin<&[mut] Field>`. //! -//! In general, deciding for which fields pinning is structural (and thus for which fields -//! pinning projections could be offered) is entirely up to the author of any given type. -//! For many types, both answers are reasonable. For example, there could be a version -//! of `Vec` with structural pinning and `get_pin`/`get_pin_mut` projections to access -//! the `Vec` elements, and another version where the contents remain movable even when -//! the `Vec` is pinned. -//! -//! However, structural pinning comes with a few extra requirements: +//! However, structural pinning comes with a few extra requirements, so not all +//! wrappers can be structural and hence not all wrappers can offer pinning projections: //! //! 1. The wrapper must only be [`Unpin`] if all the structural fields are //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of @@ -214,8 +206,9 @@ //! 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 +//! `Option<T>` and there is a `take`-like operation with type +//! `fn(Pin<&mut Wrapper<T>>) -> Option<T>`, +//! that operation can be used to move a `T` out of a pinned `Wrapper` -- which means //! pinning cannot be structural. //! //! For a more complex example of moving data out of a pinnd type, imagine if `RefCell` @@ -233,20 +226,23 @@ //! (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, -//! you are free to `impl<T> Unpin for Wrapper<T>`. In the standard library, -//! this is done for all pointer types: `Box<T>: Unpin` holds for all `T`. +//! For a type like `Vec`, both possibilites (structural pinning or not) make sense, +//! and the choice is up to the author. A `Vec` with structural pinning could +//! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling +//! `pop` on a pinned `Vec` because that would move the (structurally pinned) contents! +//! Nor could it allow `push`, which might reallocate and thus also move the contents. +//! A `Vec` without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents +//! are never pinned and the `Vec` itself is fine with being moved as well. +//! +//! In the standard library, pointer types generally do not have structural pinning, +//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`. //! It makes sense to do this for pointer types, because moving the `Box<T>` -//! does not actually move the `T`: the `Box<T>` can be freely movable even if the `T` +//! does not actually move the `T`: the `Box<T>` can be freely movable (aka `Unpin`) even if the `T` //! is not. In fact, even `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves, -//! for the same reason. -//! -//! Another case where you might want to have a wrapper without structural pinning is when even -//! a pinned wrapper lets its contents move, e.g. with a `take`-like operation. And, finally, -//! if it is not possible to satisfy the requirements for structural pinning, it makes sense -//! to add the `impl<T> Unpin for Wrapper<T>` to explicitly document this fact, and to let -//! library clients benefit from the easier interaction with [`Pin`] that [`Unpin`] types enjoy. +//! for the same reason: their contents (the `T`) are pinned, but the pointers themselves +//! can be moved without moving the pinned data. For both `Box<T>` and `Pin<Box<T>>`, +//! whether the content is pinned is entirely independent of whether the pointer is +//! pinned, meaning pinning is *not* structural. //! //! [`Pin`]: struct.Pin.html //! [`Unpin`]: ../../std/marker/trait.Unpin.html |
