Skip to content

Commit 252a83b

Browse files
fu5haManishearth
authored andcommittedJan 7, 2024
add section on manual owning ptr managed solution via @kpreid
1 parent 7c9c712 commit 252a83b

File tree

1 file changed

+36
-9
lines changed

1 file changed

+36
-9
lines changed
 

Diff for: ‎library/core/src/pin.rs

+36-9
Original file line numberDiff line numberDiff line change
@@ -163,20 +163,47 @@
163163
//! first option is ruled out.
164164
//!
165165
//! In order to implement the second option, we must in some way enforce its key invariant,
166-
//! *i.e.* prevent the value from being *moved* or otherwise invalidated. (You may notice this
167-
//! sounds an awful lot like the definition of *pinning* a value). There are two ways by
168-
//! which we might enforce this validity invariant in Rust:
166+
//! *i.e.* prevent the value from being *moved* or otherwise invalidated (you may notice this
167+
//! sounds an awful lot like the definition of *pinning* a value). There a few ways one might be
168+
//! able to enforce this invariant in Rust:
169169
//!
170170
//! 1. Offer a wholly `unsafe` API to interact with the object, thus requiring every caller to
171-
//! uphold the invariant themselves; or,
172-
//! 2. Leverage the type system to encode and enforce this invariant by presenting a restricted
173-
//! API surface to interact with the object
171+
//! uphold the invariant themselves
172+
//! 2. Store the value that must not be moved behind a carefully managed pointer internal to
173+
//! the object
174+
//! 3. Leverage the type system to encode and enforce this invariant by presenting a restricted
175+
//! API surface to interact with *any* object that requires these invariants
174176
//!
175-
//! The first option is quite obviously undesirable, as the `unsafe`ty of the interface will
177+
//! The first option is quite obviously undesirable, as the [`unsafe`]ty of the interface will
176178
//! become viral throughout all code that interacts with the object.
177179
//!
178-
//! [`Pin<Ptr>`] is an implementation of the second option, allowing us to pin a value in place
179-
//! until its [`drop`] runs in a way that we can depend on it staying valid in `unsafe` code.
180+
//! The second option is a viable solution to the problem for some use cases, in particular
181+
//! for self-referrential types. Under this model, any type that has an address sensitive state
182+
//! would ultimately store its data in something like a [`Box<T>`] and then carefully manage
183+
//! the access to that data internally to ensure no *moves* or other invalidation occur, then
184+
//! provide a safe interface on top.
185+
//!
186+
//! There are a couple of linked disadvantages to using this model. The core issue is a lack
187+
//! of generality. This is an issue first because it means hat each individual type that
188+
//! implements such an interface does so on its own. Each individual developer must themselves
189+
//! think through all the guarantees needed to ensure the API they present is sound. This puts
190+
//! a greater burden on each developer, rather than allowing building a shared understanding of the
191+
//! problem space, encoded into a shared interface to solve it. In addition, and the key issue that
192+
//! drove Rust towards another solution, is that each individual object must assume it is on its
193+
//! own in ensuring that its data does not become *moved* or otherwise invalidated. Since there is
194+
//! no shared contract between values of different types, an object cannot assume that others
195+
//! interacting with it will be a good citizen with its data. Because of this, *composition* of
196+
//! address-sensitive types requires at least a level of pointer indirection (and, practically, a
197+
//! heap allocation) each time a new object is added to the mix. This is particularly a problem
198+
//! when one considers the implications of composing together the [`Future`]s which will eventaully
199+
//! make up an asynchronous task (including address-sensitive `async fn` state machines).
200+
//! It is plausible that there could be many layers of [`Future`]s composed together, including
201+
//! multiple layers of `async fn`s handling different parts of a task, and it was deemed
202+
//! unacceptable to force indirection and allocation for each layer of composition in this case.
203+
//!
204+
//! [`Pin<Ptr>`] is an implementation of the third option. It allows us to solve the issues
205+
//! discussed with the second option by building a *shared contractual language* around the
206+
//! guarantees of "pinning" data.
180207
//!
181208
//! ## Using [`Pin<Ptr>`] to pin values
182209
//!

0 commit comments

Comments
 (0)