Skip to content

Commit 6818d92

Browse files
fu5haManishearth
authored andcommittedJan 7, 2024
improve intro and discussion of pinning as library contract
1 parent db5b19e commit 6818d92

File tree

1 file changed

+59
-39
lines changed

1 file changed

+59
-39
lines changed
 

‎library/core/src/pin.rs

+59-39
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,23 @@
1010
//!
1111
//! is called "pinning." We would say that a value which satisfies these guarantees has been
1212
//! "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].
13+
//! location in memory, as though pinned to a pinboard. Pinning a value is incredibly useful in
14+
//! that it provides the necessary guarantees[^guarantees] for [`unsafe`] code to be able to
15+
//! dereference raw pointers to the pinned value for the duration it is pinned (which,
16+
//! [as we'll see later][drop-guarantee], is necessarily from the time the value is first pinned
17+
//! until the end of its lifetime). This concept of "pinning" is necessary to implement safe
18+
//! interfaces on top of things like self-referential types and intrusive data structures which
19+
//! cannot currently be modeled in fully safe Rust using only borrow-checked
20+
//! [references][reference].
2021
//!
2122
//! "Pinning" allows us to put a *value* which exists at some location in memory into a state where
2223
//! safe code cannot *move* that value to a different location in memory or otherwise invalidate it
2324
//! 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.
25+
//! [talk about below][self#unpin]). Anything that wants to interact with the pinned value in a way
26+
//! that has the potential to violate these guarantees must promise that it will not actually
27+
//! violate them, using the [`unsafe`] keyword to mark that such a promise is upheld by the user
28+
//! and not the compiler. In this way, we can allow other [`unsafe`] code to rely on any pointers
29+
//! that point to the pinned value to be valid to dereference while it is pinned.
2930
//!
3031
//! [^guarantees]: Pinning on its own does not provide *all* the invariants necessary here. However,
3132
//! in order to validly pin a value in the first place, it must already satisfy the other invariants
@@ -61,7 +62,7 @@
6162
//! [`Copy`]ing a value from one place in memory to another. In Rust, "move" carries with it the
6263
//! semantics of ownership transfer from one variable to another, which is the key difference
6364
//! between a [`Copy`] and a move. For the purposes of this module's documentation, however, when
64-
//! we write *move* in italics, we mean *specifically* that the value has moved in the mechanical
65+
//! we write *move* in italics, we mean *specifically* that the value has *moved* in the mechanical
6566
//! sense of being located at a new place in memory.
6667
//!
6768
//! All values in Rust are trivially *moveable*. This means that the address at which a value is
@@ -184,12 +185,38 @@
184185
//! will not be *moved* or [otherwise invalidated][subtle-details].
185186
//!
186187
//! We call such a [`Pin`]-wrapped pointer a **pinning pointer,** (or pinning reference, or pinning
187-
//! `Box`, etc.) because its existince is the thing that is pinning the underlying pointee in place:
188-
//! it is the metaphorical "pin" securing the data in place on the pinboard (in memory).
188+
//! `Box`, etc.) because its existince is the thing that is *symbolically* pinning the underlying
189+
//! pointee in place: it is the metaphorical "pin" securing the data in place on the pinboard
190+
//! (in memory).
191+
//!
192+
//! Notice that the thing wrapped by [`Pin`] is not the value which we want to pin itself, but
193+
//! rather a pointer to that value! A [`Pin<Ptr>`] does not pin the `Ptr`; instead, it pins the
194+
//! pointer's ***pointee** value*.
195+
//!
196+
//! ### Pinning as a library contract
197+
//!
198+
//! Pinning does not require nor make use of any compiler "magic"[^noalias], only a specific
199+
//! contract between the [`unsafe`] parts of a library API and its users.
200+
//!
201+
//! It is important to stress this point as a user of the [`unsafe`] parts of the [`Pin`] API.
202+
//! Practically, this means that performing the mechanics of "pinning" a value by creating a
203+
//! [`Pin<Ptr>`] to it *does not* actually change the way the compiler behaves towards the
204+
//! inner value! It is possible to use incorrect [`unsafe`] code to create a [`Pin<Ptr>`] to a
205+
//! value which does not actually satisfy the invariants that a pinned value must satisfy, and in
206+
//! this way lead undefined behavior even in (from that point) fully safe code. Similarly, using
207+
//! [`unsafe`], one may get access to a bare [`&mut T`] from a [`Pin<Ptr>`] and
208+
//! juse that to invalidly *move* pinned the value out. It is the job of the user of the
209+
//! [`unsafe`] parts of the [`Pin`] API to ensure these invariants are not violated.
210+
//!
211+
//! This differs from e.g. [`UnsafeCell`] which changes the semantics of a program's compiled
212+
//! output. A [`Pin<Ptr>`] is a handle to a value which we have promised we will not move out of,
213+
//! but Rust still considers all values themselves to be fundamentally moveable through, *e.g.*
214+
//! assignment or [`mem::replace`].
189215
//!
190-
//! It is important to stress that the thing in the [`Pin`] is not the value which we want to pin
191-
//! itself, but rather a pointer to that value! A [`Pin<Ptr>`] does not pin the `Ptr` but rather
192-
//! the pointer's ***pointee** value*.
216+
//! [^noalias]: There is a bit of nuance here that is still being decided about what the aliasing
217+
//! semantics of `Pin<&mut T>` should be, but this is true as of today.
218+
//!
219+
//! ### How [`Pin`] prevents misuse in safe code
193220
//!
194221
//! In order to accomplish the goal of pinning the pointee value, [`Pin<Ptr>`] restricts access to
195222
//! the wrapped `Ptr` type in safe code. Specifically, [`Pin`] disallows the ability to access
@@ -199,23 +226,25 @@
199226
//! through that <code>[&mut] T</code> it would be possible to *move* the underlying value out of
200227
//! the pointer with [`mem::replace`], etc.
201228
//!
202-
//! This promise must be upheld manually by [`unsafe`] code which interacts with the [`Pin<Ptr>`]
203-
//! so that other [`unsafe`] code can rely on the pointee value being *un-moved* and valid.
204-
//! Interfaces that operate on values which are in an address-sensitive state accept an argument
205-
//! like <code>[Pin]<[&mut] T></code> or <code>[Pin]<[Box]\<T>></code> to indicate this contract to
206-
//! the caller.
229+
//! As discussed above, this promise must be upheld manually by [`unsafe`] code which interacts
230+
//! with the [`Pin<Ptr>`] so that other [`unsafe`] code can rely on the pointee value being
231+
//! *un-moved* and valid. Interfaces that operate on values which are in an address-sensitive state
232+
//! accept an argument like <code>[Pin]<[&mut] T></code> or <code>[Pin]<[Box]\<T>></code> to
233+
//! indicate this contract to the caller.
207234
//!
208-
//! [As discussed below][drop-guarantee], this has consequences for running
209-
//! destructors of pinned memory, too.
235+
//! [As discussed below][drop-guarantee], opting in to using pinning guarantees in the interface
236+
//! of an address-sensitive type has consequences for the implementation of some safe traits on
237+
//! that type as well.
210238
//!
211239
//! ## Interaction between [`Deref`] and [`Pin<Ptr>`]
212240
//!
213241
//! Since [`Pin<Ptr>`] can wrap any pointer type, it uses [`Deref`] and [`DerefMut`] in
214242
//! order to identify the type of the pinned pointee data and provide (restricted) access to it.
215243
//!
216-
//! A [`Pin<Ptr>`] where [`Ptr: Deref`][Deref] is a "`Ptr`-style pointer" to a pinned
217-
//! [`P::Target`][Target] – so, a <code>[Pin]<[Box]\<T>></code> is an owned pointer to a pinned `T`,
218-
//! and a <code>[Pin]<[Rc]\<T>></code> is a reference-counted pointer to a pinned `T`.
244+
//! A [`Pin<Ptr>`] where [`Ptr: Deref`][Deref] is a "`Ptr`-style pinning pointer" to a pinned
245+
//! [`P::Target`][Target] – so, a <code>[Pin]<[Box]\<T>></code> is an owned, pinning pointer to a
246+
//! pinned `T`, and a <code>[Pin]<[Rc]\<T>></code> is a reference-counted, pinning pointer to a
247+
//! pinned `T`.
219248
//!
220249
//! [`Pin<Ptr>`] also uses the [`<Ptr as Deref>::Target`][Target] type information to modify the
221250
//! interface it is allowed to provide for interacting with that data (for example, when a
@@ -228,17 +257,6 @@
228257
//! types with such "malicious" implementations of [`Deref`]; see [`Pin<Ptr>::new_unchecked`] for
229258
//! details.
230259
//!
231-
//! ## Pinning as a library contract
232-
//!
233-
//! Pinning does not require any compiler "magic"[^noalias], only a specific contract between the
234-
//! library API and its users. This differs from e.g. [`UnsafeCell`] which changes the semantics of
235-
//! a program's compiled output. A [`Pin<Ptr>`] is a handle to a value which does not allow moving
236-
//! the value out, but Rust still considers all values themselves to be moveable with e.g.
237-
//! [`mem::replace`].
238-
//!
239-
//! [^noalias]: There is a bit of nuance here that is still being decided about what the aliasing
240-
//! semantics of `Pin<&mut T>` should be, but this is true as of today.
241-
//!
242260
//! ## Fixing `AddrTracker`
243261
//!
244262
//! The guarantee of a stable address is necessary to make our `AddrTracker` example work. When
@@ -850,6 +868,7 @@
850868
//! [`std::alloc`]: ../../std/alloc/index.html
851869
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
852870
//! [Box]: ../../std/boxed/struct.Box.html "Box"
871+
//! [`Box`]: ../../std/boxed/struct.Box.html "Box"
853872
//! [`Rc<T>`]: ../../std/rc/struct.Rc.html
854873
//! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc"
855874
//! [`Vec<T>`]: ../../std/vec/struct.Vec.html
@@ -861,6 +880,7 @@
861880
//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len
862881
//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html
863882
//! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque"
883+
//! [`String`]: ../../std/string/struct.String.html "String"
864884
865885
#![stable(feature = "pin", since = "1.33.0")]
866886

0 commit comments

Comments
 (0)