Skip to content

Commit b17ecc9

Browse files
committed
improve intro and Unpin-related discussion
1 parent a7e9c3b commit b17ecc9

File tree

2 files changed

+139
-63
lines changed

2 files changed

+139
-63
lines changed

library/core/src/marker.rs

+26-16
Original file line numberDiff line numberDiff line change
@@ -879,25 +879,28 @@ marker_impls! {
879879
{T: ?Sized} &mut T,
880880
}
881881

882-
/// Types that can be safely moved after being pinned.
882+
/// Types that do not need to follow the rules of pinning.
883883
///
884-
/// Rust itself has no notion of immovable types, and considers moves (e.g.,
885-
/// through assignment or [`mem::replace`]) to always be safe.
884+
/// For information on what "pinning" is, see the [`pin` module] documentation.
886885
///
887-
/// The [`Pin`][Pin] type is used instead to prevent moves through the type
888-
/// system. Pointers `P<T>` wrapped in the [`Pin<P<T>>`][Pin] wrapper can't be
889-
/// moved out of. See the [`pin` module] documentation for more information on
890-
/// pinning.
886+
/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off that type.
887+
/// This means that, if `T: Unpin`, it cannot be assumed that a value of type `T` will be bound
888+
/// by the invariants that pinning infers, *even* when "pinned" by a [`Pin<Ptr>`] pointing at it.
889+
/// When a value of type `T` is pointed at by a [`Pin<Ptr>`], [`Pin`] will not restrict access
890+
/// to the pointee value like it normally would, thus allowing the user to do anything that they
891+
/// normally could with a non-[`Pin`]-wrapped `Ptr` to that value.
891892
///
892-
/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off
893-
/// the type, which then allows moving `T` out of [`Pin<P<T>>`][Pin] with
894-
/// functions such as [`mem::replace`].
893+
/// For more discussion on the consequences of [`Unpin`] within the wider scope of the pinning
894+
/// system, see [the section about `Unpin`] in the [`pin` module].
895895
///
896-
/// `Unpin` has no consequence at all for non-pinned data. In particular,
897-
/// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not
898-
/// just when `T: Unpin`). However, you cannot use [`mem::replace`] on data
899-
/// wrapped inside a [`Pin<P<T>>`][Pin] because you cannot get the `&mut T` you
900-
/// need for that, and *that* is what makes this system work.
896+
/// `Unpin` has no consequence at all for non-pinned data. In particular, [`mem::replace`] happily
897+
/// moves `!Unpin` data, which would be immovable when pinned ([`mem::replace`] works for any
898+
/// `&mut T`, not just when `T: Unpin`).
899+
///
900+
/// *However*, you cannot use [`mem::replace`] on `!Unpin` data which is *pinned* by being wrapped
901+
/// inside a [`Pin<Ptr>`][Pin] pointing at it. This is because you cannot (safely) use a
902+
/// [`Pin<Ptr>`] to get an `&mut T` to its pointee value, which you would need to call
903+
/// [`mem::replace`], and *that* is what makes this system work.
901904
///
902905
/// So this, for example, can only be done on types implementing `Unpin`:
903906
///
@@ -915,11 +918,18 @@ marker_impls! {
915918
/// mem::replace(&mut *pinned_string, "other".to_string());
916919
/// ```
917920
///
918-
/// This trait is automatically implemented for almost every type.
921+
/// This trait is automatically implemented for almost every type. The compiler (and you!) is free
922+
/// to take the conservative stance of marking types as [`Unpin`] by default. This is because if a
923+
/// type implements [`Unpin`], then it is unsound for [`unsafe`] code to assume that type is truly
924+
/// pinned, *even* when viewed through a "pinning" pointer! It is the responsibility of the
925+
/// implementor of [`unsafe`] code that relies upon pinning for soundness to ensure that all the
926+
/// types it expects to be truly pinned do not implement [`Unpin`]. For more details, see the
927+
/// [`pin` module] docs!
919928
///
920929
/// [`mem::replace`]: crate::mem::replace
921930
/// [Pin]: crate::pin::Pin
922931
/// [`pin` module]: crate::pin
932+
/// [section about `Unpin`]: crate::pin#unpin
923933
#[stable(feature = "pin", since = "1.33.0")]
924934
#[rustc_on_unimplemented(
925935
note = "consider using the `pin!` macro\nconsider using `Box::pin` if you need to access the pinned value outside of the current scope",

library/core/src/pin.rs

+113-47
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,53 @@
11
//! Types that pin data to a location in memory.
22
//!
33
//! It is sometimes useful to be able to rely upon a certain value not being able to *move*,
4-
//! in the sense that its address in memory cannot change. This is useful specifically when there
5-
//! are one or more *pointers* pointing at that value. The ability to rely on this guarantee that
6-
//! the value a pointer is pointing at (its **pointee**) will
4+
//! in the sense that its address in memory cannot change. This is useful especially when there
5+
//! are one or more [*pointers*][pointer] pointing at that value. The ability to rely on this
6+
//! guarantee that the value a [pointer] is pointing at (its **pointee**) will
77
//!
88
//! 1. Not be *moved* out of its memory location
99
//! 2. More generally, remain *valid* at that same memory location
1010
//!
11-
//! is necessary to implement things like self-referential structs and intrusive data structures.
12-
//!
13-
//! "Pinning" allows us to put a value *which is being pointed at* by some pointer `Ptr` into a
14-
//! state that prevents safe code from *moving* or otherwise invalidating the *pointee* value at
15-
//! its location in memory (unless the pointee type implements [`Unpin`], which we'll
16-
//! [discuss more below][self#unpin]). In this way, we can allow [`unsafe`] code to rely on the
17-
//! pointer to be valid to dereference.
11+
//! is called "pinning." We would say that a value which satisfies these guarantees has been
12+
//! "pinned," in that it has been permanently (until the end of its lifetime) attached to its
13+
//! location in memory. Pinning a value is incredibly useful in that it provides the necessary
14+
//! guarantees[^guarantees] for [`unsafe`] code to be able to dereference raw pointers to the pinned
15+
//! value for the duration it is pinned (which, [as we'll see later][drop-guarantee], is necessarily
16+
//! from the time the value is first pinned until the end of its lifetime). This concept of
17+
//! "pinning" is necessary to implement safe interfaces on top of things like self-referential types
18+
//! and intrusive data structures which cannot currently be modeled in fully safe Rust using only
19+
//! borrow-checked [references][reference].
20+
//!
21+
//! "Pinning" allows us to put a *value* which exists at some location in memory into a state where
22+
//! safe code cannot *move* that value to a different location in memory or otherwise invalidate it
23+
//! at its current location (unless it implements [`Unpin`], which we will
24+
//! [talk about below][unpin]). Anything that wants to interact with the pinned value in a way that
25+
//! has the potential to violate these guarantees must promise that it will not actually violate
26+
//! them, using the [`unsafe`] keyword to mark that such a promise is upheld by the user and not
27+
//! the compiler. In this way, we can allow other [`unsafe`] code to rely on any pointers that
28+
//! point to the pinned value to be valid to dereference while it is pinned.
29+
//!
30+
//! [^guarantees]: Pinning on its own does not provide *all* the invariants necessary here. However,
31+
//! in order to validly pin a value in the first place, it must already satisfy the other invariants
32+
//! for it to be valid to dereference a pointer to that value while it is pinned, and using the
33+
//! [`Drop` guarantee][drop-guarantee], we can ensure that any interested parties are notified
34+
//! before the value becomes no longer pinned, i.e. when the value goes out of scope and is
35+
//! invalidated.
36+
//!
37+
//! Note that as long as you don't use [`unsafe`], it's impossible to create or misuse a pinned
38+
//! value in a way that will produce unsoundness. See the documentation of [`Pin<Ptr>`] for more
39+
//! information on the practicalities of how to pin a value and how to use that pinned value from a
40+
//! user's perspective without using [`unsafe`].
1841
//!
1942
//! The rest of this documentation is intended to be the source of truth for users of [`Pin<Ptr>`]
20-
//! in unsafe code; users of [`Pin<Ptr>`] in safe code do not need to read it in detail.
43+
//! that are implementing the [`unsafe`] pieces of an interface that relies on pinning for validity;
44+
//! users of [`Pin<Ptr>`] in safe code do not need to read it in detail.
2145
//!
2246
//! There are several sections to this documentation:
2347
//!
2448
//! * [What is "*moving*"?][what-is-moving]
2549
//! * [What is "pinning"?][what-is-pinning]
50+
//! * [Address sensitivity, AKA "when do we need pinning?"][address-sensitive-values]
2651
//! * [Examples of types with address-sensitive states][address-sensitive-examples]
2752
//! * [Self-referential struct][self-ref]
2853
//! * [Intrusive, doubly-linked list][linked-list]
@@ -90,8 +115,8 @@
90115
//! to remain *valid* and *located at the same place in memory* from the time it is pinned until its
91116
//! [`drop`] is called.
92117
//!
93-
//! ## Address-sensitive values, AKA "why we need pinning"
94-
//! [address-sensitive-values]: self#address-sensitive-values
118+
//! ## Address-sensitive values, AKA "when we need pinning"
119+
//! [address-sensitive-values]: self#address-sensitive-values-aka-when-we-need-pinning
95120
//!
96121
//! Most values in Rust are entirely okay with being *moved* around at-will.
97122
//! Types for which it is *always* the case that *any* value of that type can be
@@ -105,9 +130,9 @@
105130
//!
106131
//! As a motivating example of a type which may become address-sensitive, consider a type which
107132
//! contains a pointer to another piece of its own data, *i.e.* a "self-referential" type. In order
108-
//! such a type to be implemented soundly, the pointer which points into `self`'s data must be
133+
//! for such a type to be implemented soundly, the pointer which points into `self`'s data must be
109134
//! proven valid whenever it is accessed. But if that value is *moved*, the pointer will still
110-
//! point to the old location that the value was located and not into the new location of `self`,
135+
//! point to the old address where the value was located and not into the new location of `self`,
111136
//! thus becoming invalid. A key example of such self-referrential types are the state machines
112137
//! generated by the compiler to implement [`Future`] for `async fn`s.
113138
//!
@@ -122,7 +147,7 @@
122147
//! assume that the address of the value is stable
123148
//! * e.g. subsequent calls to [`poll`]
124149
//! 4. Before the value is invalidated (e.g. deallocated), it is *dropped*, giving it a chance to
125-
//! "unregister"/clear outstanding pointers to itself
150+
//! notify anything with pointers to itself that those pointers will be invalidated
126151
//! * e.g. [`drop`]ping the [`Future`]
127152
//!
128153
//! There are two possible ways to ensure the invariants required for 2. and 3. above (which
@@ -229,8 +254,9 @@
229254
//! #[derive(Default)]
230255
//! struct AddrTracker {
231256
//! prev_addr: Option<usize>,
232-
//! // remove auto-implemented Unpin bound to mark this type as having some
233-
//! // address-sensitive state. This is discussed more below.
257+
//! // remove auto-implemented `Unpin` bound to mark this type as having some
258+
//! // address-sensitive state. This is essential for our expected pinning
259+
//! // guarantees to work, and is discussed more below.
234260
//! _pin: PhantomPinned,
235261
//! }
236262
//!
@@ -273,25 +299,52 @@
273299
//!
274300
//! The vast majority of Rust types have no address-sensitive states; these types
275301
//! implement the [`Unpin`] auto-trait, which cancels the restrictive effects of
276-
//! [`Pin<P>`]. When [`T: Unpin`][Unpin], <code>[Pin]<[Box]\<T>></code> and
277-
//! [`Box<T>`] function identically, as do <code>[Pin]<[&mut] T></code> and
278-
//! [`&mut T`].
302+
//! [`Pin`] when the *pointee* type `T` is [`Unpin`]. When [`T: Unpin`][Unpin],
303+
//! <code>[Pin]<[Box]\<T>></code> functions identically to a non-pinning [`Box<T>`]; similarly,
304+
//! <code>[Pin]<[&mut] T></code> would impose no additional restrictions above a regular [`&mut T`].
305+
//!
306+
//! Note that the interaction between a [`Pin<Ptr>`] and [`Unpin`] is through the type of the
307+
//! **pointee** value, [`<Ptr as Deref>::Target`][Target]. Whether the `Ptr` type itself
308+
//! implements [`Unpin`] does not affect the behavior of a [`Pin<Ptr>`]. For example, whether or not
309+
//! [`Box`] is [`Unpin`] has no effect on the behavior of <code>[Pin]<[Box]\<T>></code>, because
310+
//! `T` is the type of the pointee value, not [`Box`]. So, whether `T` implements [`Unpin`] is
311+
//! the thing that will affect the behavior of the <code>[Pin]<[Box]\<T>></code>.
279312
//!
280-
//! This includes all of the primitive types, like [`bool`], [`i32`], and <code>[&]T</code>,
281-
//! as well as any other type consisting only of those types.
313+
//! Builtin types that are [`Unpin`] include all of the primitive types, like [`bool`], [`i32`],
314+
//! and [`f32`], references (<code>[&]T</code> and <code>[&mut] T</code>), etc., as well as many
315+
//! core and standard library types like [`Box<T>`], [`String`], and more.
316+
//! These types are marked [`Unpin`] because they do not have an ddress-sensitive state like the
317+
//! ones we discussed above. If they did have such a state, those parts of their interface would be
318+
//! unsound without being expressed through pinning, and they would then need to not
319+
//! implement [`Unpin`].
320+
//!
321+
//! The compiler (and users!) is free to take the conservative stance of marking types as [`Unpin`]
322+
//! by default. This is because if a type implements [`Unpin`], then it is unsound for [`unsafe`]
323+
//! code to assume that type is truly pinned, *even* when viewed through a "pinning" pointer! It is
324+
//! the responsibility of *the implementor of [`unsafe`] code that relies upon pinning for
325+
//! soundness* (you, in this case!) to ensure that all the types which that code expects to be truly
326+
//! pinned do not implement [`Unpin`].
282327
//!
283328
//! Like other auto-traits, the compiler will automatically determine that a type implements
284-
//! [`Unpin`] if all its fields also implement [`Unpin`]. If you are building a type which is built
329+
//! [`Unpin`] if all its fields also implement [`Unpin`]. If you are building a type which consists
285330
//! of only [`Unpin`] types but has an address-sensistive state and thus should not itself
286-
//! implement [`Unpin`], you can opt out of [`Unpin`] via adding a field with the
287-
//! [`PhantomPinned`] marker type, as we did with our latest `AddrTracker` example above.
288-
//!
289-
//! Note that the interaction between a [`Pin<Ptr>`] and [`Unpin`] is through the **pointee type**
290-
//! of the value behind the `Ptr`, [`<Ptr as Deref>::Target`][Target]. Whether the `Ptr` type itself
291-
//! implements [`Unpin`] does not affect the behavior of a [`Pin<Ptr>`]. For example, whether or not
292-
//! [`Box<T>`] is [`Unpin`] has no effect on the behavior of <code>[Pin]<[Box]\<T>></code> because
293-
//! `T` is the type of the pointee value, not [`Box<T>`]. So, whether `T` implements [`Unpin`] is
294-
//! the thing that will affect the behavior of the <code>[Pin]<[Box]\<T>></code>.
331+
//! implement [`Unpin`], you must opt out of [`Unpin`] via adding a field with the
332+
//! [`PhantomPinned`] marker type, as we did with our latest `AddrTracker` example above. Without
333+
//! doing this, you must not rely on the pinning guarantees to apply to your type!
334+
//!
335+
//! If you have reason to pin a value of a type that implements [`Unpin`] such that pinning-related
336+
//! guarantees actually are respected, you'll need to create your own wrapper type which itself
337+
//! opts out of implementing [`Unpin`] and contains a sub-field with the [`Unpin`] type that you
338+
//! want to pin.
339+
//!
340+
//! Exposing access to the inner field which you want to remain pinned must then be carefully
341+
//! considered as well! Remember, exposing a method that gives access to a
342+
//! <code>[Pin]<[&mut] InnerT>></code> where `InnerT: [Unpin]` would allow safe code to trivially
343+
//! move the inner value out of that pinning pointer, which is precisely what you're seeking to
344+
//! prevent! Exposing a field of a pinned value through a pinning pointer is called "projecting"
345+
//! a pin, and the more general case of deciding in which cases a pin should be able to be
346+
//! projected or not is called "structural pinning." We will go into more detail about this
347+
//! [below][structural-pinning].
295348
//!
296349
//! # Examples of address-sensitive types
297350
//! [address-sensitive-examples]: #examples-of-address-sensitive-types
@@ -308,7 +361,7 @@
308361
//! we could imagine being used to track a sliding window of `data` in parser
309362
//! code.
310363
//!
311-
//! As mentioned before, this pattern is used extensively by compiler-generated
364+
//! As mentioned before, this pattern is also used extensively by compiler-generated
312365
//! [`Future`]s.
313366
//!
314367
//! ```rust
@@ -379,27 +432,39 @@
379432
//! ## An intrusive, doubly-linked list
380433
//! [linked-list]: #an-intrusive-doubly-linked-list
381434
//!
382-
//! In an intrusive doubly-linked list, the collection does not actually allocate the memory for the
383-
//! nodes itself. Allocation is controlled by the clients, and nodes can live on a stack frame
384-
//! that lives shorter than the collection does provided the nodes are removed from the
385-
//! collection before returning.
435+
//! In an intrusive doubly-linked list, the collection itself does not own the memory in which
436+
//! each of its elements is stored. Instead, each client is free to allocate space for elements it
437+
//! adds to the list in whichever manner it likes, including on the stack! Elements can live on a
438+
//! stack frame that lives shorter than the collection does provided the elements that live in a
439+
//! given stack frame are removed from the list before going out of scope.
440+
//!
441+
//! To make such an intrusive data structure work, every element stores pointers to its predecessor
442+
//! and successor within its own data, rather than having the list structure itself managing those
443+
//! pointers. It is in this sense that the structure is "intrusive": the details of how an
444+
//! element is stored within the larger structure "intrudes" on the implementation of the element
445+
//! type itself!
386446
//!
387447
//! The full implementation details of such a data structure are outside the scope of this
388448
//! documentation, but we will discuss how [`Pin`] can help to do so.
389449
//!
390-
//! To make such an intrusive data structure work, every element stores pointers to its predecessor
391-
//! and successor within its own data, rather than having the list structure itself manage those
392-
//! pointers. Elements can only be added when they are pinned, because moving the elements
393-
//! around would invalidate the pointers to it which are contained in the element ahead and behind
394-
//! it. Moreover, the [`Drop`][Drop] implementation of the element types themselves will in some
395-
//! way patch the pointers of its predecessor and successor elements to remove itself from the list.
450+
//! Using such an intrusive pattern, elements may only be added when they are pinned. If we think
451+
//! about the consequences of adding non-pinned values to such a list, this becomes clear:
452+
//!
453+
//! *Moving* or otherwise invalidating an element's data would invalidate the pointers back to it
454+
//! which are stored in the elements ahead and behind it. Thus, in order to soundly dereference
455+
//! the pointers stored to the next and previous elements, we must satisfy the guarantee that
456+
//! nothing has invalidated those pointers (which point to data which we do not own).
457+
//!
458+
//! Moreover, the [`Drop`][Drop] implementation of each element must in some way notify its
459+
//! predecessor and successor elements that it should be removed from the list before it is fully
460+
//! destroyed, otherwise the pointers back to it would again become invalidated.
396461
//!
397-
//! Crucially, this means we have to be able to rely on [`drop`] always being called before that
462+
//! Crucially, this means we have to be able to rely on [`drop`] always being called before an
398463
//! element is invalidated. If an element could be deallocated or otherwise invalidated without
399-
//! calling [`drop`], the pointers into it which are stored in its neighboring elements would
464+
//! calling [`drop`], the pointers to it which are stored in its neighboring elements would
400465
//! become invalid, which would break the data structure.
401466
//!
402-
//! Therefore, we rely on [the `Drop` guarantee][drop-guarantee] which comes with pinning data,
467+
//! Therefore, pinning data also comes with [the "`Drop` guarantee"][drop-guarantee].
403468
//!
404469
//! # Subtle details and the `Drop` guarantee
405470
//! [subtle-details]: self#subtle-details-and-the-drop-guarantee
@@ -586,6 +651,7 @@
586651
//! the new value.
587652
//!
588653
//! ## Projections and Structural Pinning
654+
//! [structural-pinning]: self#projections-and-structural-pinning
589655
//!
590656
//! With ordinary structs, it is natural that we want to add *projection* methods
591657
//! that select one of the fields:

0 commit comments

Comments
 (0)