Skip to content

Commit 59bdb31

Browse files
committed
final pin projections tweaking
1 parent c9ade6a commit 59bdb31

File tree

1 file changed

+23
-27
lines changed

1 file changed

+23
-27
lines changed

src/libcore/pin.rs

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -177,20 +177,12 @@
177177
//! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`)
178178
//! have an operation with type `fn(Pin<&[mut] Wrapper<T>>) -> Pin<&[mut] T>`?
179179
//!
180-
//! This question is closely related to the question of whether pinning is "structural".
181-
//! Structural pinning means that when you have pinned a wrapper type, the contents are
182-
//! also pinned. Structural pinning thus explains why pinning projections are correct. This means
183-
//! that if the type should have pinning projections for some fields, pinning must be structural
184-
//! for those fields.
180+
//! Having a pinning projection for some field means that pinning is "structural":
181+
//! when the wrapper is pinned, the field must be considered pinned, too.
182+
//! After all, the pinning projection lets us get a `Pin<&[mut] Field>`.
185183
//!
186-
//! In general, deciding for which fields pinning is structural (and thus for which fields
187-
//! pinning projections could be offered) is entirely up to the author of any given type.
188-
//! For many types, both answers are reasonable. For example, there could be a version
189-
//! of `Vec` with structural pinning and `get_pin`/`get_pin_mut` projections to access
190-
//! the `Vec` elements, and another version where the contents remain movable even when
191-
//! the `Vec` is pinned.
192-
//!
193-
//! However, structural pinning comes with a few extra requirements:
184+
//! However, structural pinning comes with a few extra requirements, so not all
185+
//! wrappers can be structural and hence not all wrappers can offer pinning projections:
194186
//!
195187
//! 1. The wrapper must only be [`Unpin`] if all the structural fields are
196188
//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
@@ -214,8 +206,9 @@
214206
//! does not cause unsoundness.)
215207
//! 4. You must not offer any other operations that could lead to data being moved out of
216208
//! the fields when your type is pinned. For example, if the wrapper contains an
217-
//! `Option<T>` and there is an operation such as `fn(Pin<&mut Wrapper<T>>) -> Option<T>`,
218-
//! that operation can be used to move a `T` out of a pinned `Wrapper` -- that means
209+
//! `Option<T>` and there is a `take`-like operation with type
210+
//! `fn(Pin<&mut Wrapper<T>>) -> Option<T>`,
211+
//! that operation can be used to move a `T` out of a pinned `Wrapper` -- which means
219212
//! pinning cannot be structural.
220213
//!
221214
//! For a more complex example of moving data out of a pinnd type, imagine if `RefCell`
@@ -233,20 +226,23 @@
233226
//! (using `RefCell::get_pin_mut`) and then move that content using the mutable
234227
//! reference we got later.
235228
//!
236-
//! On the other hand, if you decide *not* to offer any pinning projections, you
237-
//! do not have to do anything. If your type also does not do any pinning itself,
238-
//! you are free to `impl<T> Unpin for Wrapper<T>`. In the standard library,
239-
//! this is done for all pointer types: `Box<T>: Unpin` holds for all `T`.
229+
//! For a type like `Vec`, both possibilites (structural pinning or not) make sense,
230+
//! and the choice is up to the author. A `Vec` with structural pinning could
231+
//! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling
232+
//! `pop` on a pinned `Vec` because that would move the (structurally pinned) contents!
233+
//! Nor could it allow `push`, which might reallocate and thus also move the contents.
234+
//! A `Vec` without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents
235+
//! are never pinned and the `Vec` itself is fine with being moved as well.
236+
//!
237+
//! In the standard library, pointer types generally do not have structural pinning,
238+
//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`.
240239
//! It makes sense to do this for pointer types, because moving the `Box<T>`
241-
//! does not actually move the `T`: the `Box<T>` can be freely movable even if the `T`
240+
//! does not actually move the `T`: the `Box<T>` can be freely movable (aka `Unpin`) even if the `T`
242241
//! is not. In fact, even `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves,
243-
//! for the same reason.
244-
//!
245-
//! Another case where you might want to have a wrapper without structural pinning is when even
246-
//! a pinned wrapper lets its contents move, e.g. with a `take`-like operation. And, finally,
247-
//! if it is not possible to satisfy the requirements for structural pinning, it makes sense
248-
//! to add the `impl<T> Unpin for Wrapper<T>` to explicitly document this fact, and to let
249-
//! library clients benefit from the easier interaction with [`Pin`] that [`Unpin`] types enjoy.
242+
//! for the same reason: their contents (the `T`) are pinned, but the pointers themselves
243+
//! can be moved without moving the pinned data. For both `Box<T>` and `Pin<Box<T>>`,
244+
//! whether the content is pinned is entirely independent of whether the pointer is
245+
//! pinned, meaning pinning is *not* structural.
250246
//!
251247
//! [`Pin`]: struct.Pin.html
252248
//! [`Unpin`]: ../../std/marker/trait.Unpin.html

0 commit comments

Comments
 (0)