Skip to content

Commit d5f36b8

Browse files
authored
Rollup merge of rust-lang#61878 - RalfJung:pin, r=Dylan-DPC
improve pinning projection docs This tries to improve the explanation of structural pinning and pinning projections based on [this URLO thread](https://users.rust-lang.org/t/when-is-it-safe-to-move-a-member-value-out-of-a-pinned-future/28182). Fixes rust-lang#61272.
2 parents a6b5d22 + bf03a3c commit d5f36b8

File tree

1 file changed

+130
-41
lines changed

1 file changed

+130
-41
lines changed

src/libcore/pin.rs

+130-41
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,11 @@
138138
//! To make this work, not just moving the data is restricted; deallocating, repurposing, or
139139
//! otherwise invalidating the memory used to store the data is restricted, too.
140140
//! Concretely, for pinned data you have to maintain the invariant
141-
//! that *its memory will not get invalidated from the moment it gets pinned until
141+
//! that *its memory will not get invalidated or repurposed from the moment it gets pinned until
142142
//! when `drop` is called*. Memory can be invalidated by deallocation, but also by
143143
//! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements
144-
//! off of a vector.
144+
//! off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without
145+
//! calling the destructor first.
145146
//!
146147
//! This is exactly the kind of guarantee that the intrusive linked list from the previous
147148
//! section needs to function correctly.
@@ -166,57 +167,130 @@
166167
//! implementation as well: if an element of your type could have been pinned,
167168
//! you must treat Drop as implicitly taking `Pin<&mut Self>`.
168169
//!
169-
//! In particular, if your type is `#[repr(packed)]`, the compiler will automatically
170+
//! For example, you could implement `Drop` as follows:
171+
//! ```rust,no_run
172+
//! # use std::pin::Pin;
173+
//! # struct Type { }
174+
//! impl Drop for Type {
175+
//! fn drop(&mut self) {
176+
//! // `new_unchecked` is okay because we know this value is never used
177+
//! // again after being dropped.
178+
//! inner_drop(unsafe { Pin::new_unchecked(self)});
179+
//! fn inner_drop(this: Pin<&mut Type>) {
180+
//! // Actual drop code goes here.
181+
//! }
182+
//! }
183+
//! }
184+
//! ```
185+
//! The function `inner_drop` has the type that `drop` *should* have, so this makes sure that
186+
//! you do not accidentally use `self`/`this` in a way that is in conflict with pinning.
187+
//!
188+
//! Moreover, if your type is `#[repr(packed)]`, the compiler will automatically
170189
//! move fields around to be able to drop them. As a consequence, you cannot use
171190
//! pinning with a `#[repr(packed)]` type.
172191
//!
173192
//! # Projections and Structural Pinning
174193
//!
175-
//! One interesting question arises when considering the interaction of pinning
176-
//! and the fields of a struct. When can a struct have a "pinning projection",
177-
//! i.e., an operation with type `fn(Pin<&Struct>) -> Pin<&Field>`? In a
178-
//! similar vein, when can a generic wrapper type (such as `Vec<T>`, `Box<T>`,
179-
//! or `RefCell<T>`) have an operation with type `fn(Pin<&Wrapper<T>>) ->
180-
//! Pin<&T>`?
181-
//!
182-
//! Note: For the entirety of this discussion, the same applies for mutable references as it
183-
//! does for shared references.
194+
//! When working with pinned structs, the question arises how one can access the
195+
//! fields of that struct in a method that takes just `Pin<&mut Struct>`.
196+
//! The usual approach is to write helper methods (so called *projections*)
197+
//! that turn `Pin<&mut Struct>` into a reference to the field, but what
198+
//! type should that reference have? Is it `Pin<&mut Field>` or `&mut Field`?
199+
//! The same question arises with the fields of an `enum`, and also when considering
200+
//! container/wrapper types such as [`Vec<T>`], [`Box<T>`], or [`RefCell<T>`].
201+
//! (This question applies to both mutable and shared references, we just
202+
//! use the more common case of mutable references here for illustration.)
203+
//!
204+
//! It turns out that it is actually up to the author of the data structure
205+
//! to decide whether the pinned projection for a particular field turns
206+
//! `Pin<&mut Struct>` into `Pin<&mut Field>` or `&mut Field`. There are some
207+
//! constraints though, and the most important constraint is *consistency*:
208+
//! every field can be *either* projected to a pinned reference, *or* have
209+
//! pinning removed as part of the projection. If both are done for the same field,
210+
//! that will likely be unsound!
211+
//!
212+
//! As the author of a data structure you get to decide for each field whether pinning
213+
//! "propagates" to this field or not. Pinning that propagates is also called "structural",
214+
//! because it follows the structure of the type.
215+
//! In the following subsections, we describe the considerations that have to be made
216+
//! for either choice.
217+
//!
218+
//! ## Pinning *is not* structural for `field`
219+
//!
220+
//! It may seem counter-intuitive that the field of a pinned struct might not be pinned,
221+
//! but that is actually the easiest choice: if a `Pin<&mut Field>` is never created,
222+
//! nothing can go wrong! So, if you decide that some field does not have structural pinning,
223+
//! all you have to ensure is that you never create a pinned reference to that field.
224+
//!
225+
//! Fields without structural pinning may have a projection method that turns
226+
//! `Pin<&mut Struct>` into `&mut Field`:
227+
//! ```rust,no_run
228+
//! # use std::pin::Pin;
229+
//! # type Field = i32;
230+
//! # struct Struct { field: Field }
231+
//! impl Struct {
232+
//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> &'a mut Field {
233+
//! // This is okay because `field` is never considered pinned.
234+
//! unsafe { &mut self.get_unchecked_mut().field }
235+
//! }
236+
//! }
237+
//! ```
184238
//!
185-
//! Having a pinning projection for some field means that pinning is "structural":
186-
//! when the wrapper is pinned, the field must be considered pinned, too.
187-
//! After all, the pinning projection lets us get a `Pin<&Field>`.
239+
//! You may also `impl Unpin for Struct` *even if* the type of `field`
240+
//! is not `Unpin`. What that type thinks about pinning is not relevant
241+
//! when no `Pin<&mut Field>` is ever created.
242+
//!
243+
//! ## Pinning *is* structural for `field`
244+
//!
245+
//! The other option is to decide that pinning is "structural" for `field`,
246+
//! meaning that if the struct is pinned then so is the field.
247+
//!
248+
//! This allows writing a projection that creates a `Pin<&mut Field>`, thus
249+
//! witnessing that the field is pinned:
250+
//! ```rust,no_run
251+
//! # use std::pin::Pin;
252+
//! # type Field = i32;
253+
//! # struct Struct { field: Field }
254+
//! impl Struct {
255+
//! fn pin_get_field<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut Field> {
256+
//! // This is okay because `field` is pinned when `self` is.
257+
//! unsafe { self.map_unchecked_mut(|s| &mut s.field) }
258+
//! }
259+
//! }
260+
//! ```
188261
//!
189-
//! However, structural pinning comes with a few extra requirements, so not all
190-
//! wrappers can be structural and hence not all wrappers can offer pinning projections:
262+
//! However, structural pinning comes with a few extra requirements:
191263
//!
192-
//! 1. The wrapper must only be [`Unpin`] if all the structural fields are
264+
//! 1. The struct must only be [`Unpin`] if all the structural fields are
193265
//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
194-
//! the wrapper it is your responsibility *not* to add something like
195-
//! `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation
266+
//! the struct it is your responsibility *not* to add something like
267+
//! `impl<T> Unpin for Struct<T>`. (Notice that adding a projection operation
196268
//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break
197269
//! the principle that you only have to worry about any of this if you use `unsafe`.)
198-
//! 2. The destructor of the wrapper must not move structural fields out of its argument. This
270+
//! 2. The destructor of the struct must not move structural fields out of its argument. This
199271
//! is the exact point that was raised in the [previous section][drop-impl]: `drop` takes
200-
//! `&mut self`, but the wrapper (and hence its fields) might have been pinned before.
272+
//! `&mut self`, but the struct (and hence its fields) might have been pinned before.
201273
//! You have to guarantee that you do not move a field inside your `Drop` implementation.
202-
//! In particular, as explained previously, this means that your wrapper type must *not*
274+
//! In particular, as explained previously, this means that your struct must *not*
203275
//! be `#[repr(packed)]`.
276+
//! See that section for how to write `drop` in a way that the compiler can help you
277+
//! not accidentally break pinning.
204278
//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]:
205-
//! once your wrapper is pinned, the memory that contains the
279+
//! once your struct is pinned, the memory that contains the
206280
//! content is not overwritten or deallocated without calling the content's destructors.
207-
//! This can be tricky, as witnessed by `VecDeque<T>`: the destructor of `VecDeque<T>` can fail
208-
//! to call `drop` on all elements if one of the destructors panics. This violates the
281+
//! This can be tricky, as witnessed by [`VecDeque<T>`]: the destructor of `VecDeque<T>`
282+
//! can fail to call `drop` on all elements if one of the destructors panics. This violates the
209283
//! `Drop` guarantee, because it can lead to elements being deallocated without
210284
//! their destructor being called. (`VecDeque` has no pinning projections, so this
211285
//! does not cause unsoundness.)
212286
//! 4. You must not offer any other operations that could lead to data being moved out of
213-
//! the fields when your type is pinned. For example, if the wrapper contains an
287+
//! the structural fields when your type is pinned. For example, if the struct contains an
214288
//! `Option<T>` and there is a `take`-like operation with type
215-
//! `fn(Pin<&mut Wrapper<T>>) -> Option<T>`,
216-
//! that operation can be used to move a `T` out of a pinned `Wrapper<T>` -- which means
217-
//! pinning cannot be structural.
289+
//! `fn(Pin<&mut Struct<T>>) -> Option<T>`,
290+
//! that operation can be used to move a `T` out of a pinned `Struct<T>` -- which means
291+
//! pinning cannot be structural for the field holding this data.
218292
//!
219-
//! For a more complex example of moving data out of a pinned type, imagine if `RefCell<T>`
293+
//! For a more complex example of moving data out of a pinned type, imagine if [`RefCell<T>`]
220294
//! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`.
221295
//! Then we could do the following:
222296
//! ```compile_fail
@@ -231,13 +305,16 @@
231305
//! (using `RefCell::get_pin_mut`) and then move that content using the mutable
232306
//! reference we got later.
233307
//!
234-
//! For a type like `Vec<T>`, both possibilites (structural pinning or not) make sense,
235-
//! and the choice is up to the author. A `Vec<T>` with structural pinning could
236-
//! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling
308+
//! ## Examples
309+
//!
310+
//! For a type like [`Vec<T>`], both possibilites (structural pinning or not) make sense.
311+
//! A `Vec<T>` with structural pinning could have `get_pin`/`get_pin_mut` methods to get
312+
//! pinned references to elements. However, it could *not* allow calling
237313
//! `pop` on a pinned `Vec<T>` because that would move the (structurally pinned) contents!
238314
//! Nor could it allow `push`, which might reallocate and thus also move the contents.
239315
//! A `Vec<T>` without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents
240316
//! are never pinned and the `Vec<T>` itself is fine with being moved as well.
317+
//! At that point pinning just has no effect on the vector at all.
241318
//!
242319
//! In the standard library, pointer types generally do not have structural pinning,
243320
//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`.
@@ -249,16 +326,28 @@
249326
//! whether the content is pinned is entirely independent of whether the pointer is
250327
//! pinned, meaning pinning is *not* structural.
251328
//!
329+
//! When implementing a [`Future`] combinator, you will usually need structural pinning
330+
//! for the nested futures, as you need to get pinned references to them to call `poll`.
331+
//! But if your combinator contains any other data that does not need to be pinned,
332+
//! you can make those fields not structural and hence freely access them with a
333+
//! mutable reference even when you just have `Pin<&mut Self>` (such as in your own
334+
//! `poll` implementation).
335+
//!
252336
//! [`Pin<P>`]: struct.Pin.html
253-
//! [`Unpin`]: ../../std/marker/trait.Unpin.html
254-
//! [`Deref`]: ../../std/ops/trait.Deref.html
255-
//! [`DerefMut`]: ../../std/ops/trait.DerefMut.html
256-
//! [`mem::swap`]: ../../std/mem/fn.swap.html
257-
//! [`mem::forget`]: ../../std/mem/fn.forget.html
337+
//! [`Unpin`]: ../marker/trait.Unpin.html
338+
//! [`Deref`]: ../ops/trait.Deref.html
339+
//! [`DerefMut`]: ../ops/trait.DerefMut.html
340+
//! [`mem::swap`]: ../mem/fn.swap.html
341+
//! [`mem::forget`]: ../mem/fn.forget.html
258342
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
343+
//! [`Vec<T>`]: ../../std/vec/struct.Vec.html
259344
//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len
260-
//! [`None`]: ../../std/option/enum.Option.html#variant.None
261-
//! [`Some(v)`]: ../../std/option/enum.Option.html#variant.Some
345+
//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html
346+
//! [`RefCell<T>`]: ../cell/struct.RefCell.html
347+
//! [`None`]: ../option/enum.Option.html#variant.None
348+
//! [`Some(v)`]: ../option/enum.Option.html#variant.Some
349+
//! [`ptr::write`]: ../ptr/fn.write.html
350+
//! [`Future`]: ../future/trait.Future.html
262351
//! [drop-impl]: #drop-implementation
263352
//! [drop-guarantee]: #drop-guarantee
264353

0 commit comments

Comments
 (0)