Skip to content

Commit 0ba99f6

Browse files
committed
more work on projections and RefCell example
1 parent 442c486 commit 0ba99f6

File tree

1 file changed

+22
-12
lines changed

1 file changed

+22
-12
lines changed

src/libcore/pin.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,22 +149,23 @@
149149
//! of your type could have been pinned, you must treat Drop as implicitly taking
150150
//! `Pin<&mut Self>`.
151151
//!
152+
//! In particular, if your type is `#[repr(packed)]`, the compiler will automatically
153+
//! move fields around to be able to drop them. As a consequence, you cannot use
154+
//! pinning with a `#[repr(packed)]` type.
155+
//!
152156
//! # Projections and Structural Pinning
153157
//!
154158
//! One interesting question arises when considering the interaction of pinning and
155-
//! the fields of a struct. When can a struct have a "projection operation", i.e.,
159+
//! the fields of a struct. When can a struct have a "pinning projection", i.e.,
156160
//! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`?
157161
//! In a similar vein, when can a container type (such as `Vec`, `Box`, or `RefCell`)
158162
//! have an operation with type `fn(Pin<&[mut] Container<T>>) -> Pin<&[mut] T>`?
159163
//!
160164
//! This question is closely related to the question of whether pinning is "structural":
161-
//! when you have pinned a wrapper type, have you pinned its contents? Adding a
165+
//! when you have pinned a wrapper type, have you pinned its contents? Deciding this
166+
//! is entirely up to the author of any given type. However, adding a
162167
//! projection to the API answers that question with a "yes" by offering pinned access
163-
//! to the contents.
164-
//!
165-
//! In general, as the author of a type you get to decide whether pinning is structural, and
166-
//! whether projections are provided. However, there are a couple requirements to be
167-
//! upheld when adding projection operations:
168+
//! to the contents. In that case, there are a couple requirements to be upheld:
168169
//!
169170
//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are
170171
//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
@@ -185,15 +186,24 @@
185186
//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail
186187
//! to call `drop` on all elements if one of the destructors panics. This violates the
187188
//! `Drop` guarantee, because it can lead to elements being deallocated without
188-
//! their destructor being called.
189+
//! their destructor being called. (`VecDeque` has no pinning projections, so this
190+
//! does not cause unsoundness.)
189191
//! 5. You must not offer any other operations that could lead to data being moved out of
190192
//! the fields when your type is pinned. This is usually not a concern, but can become
191193
//! tricky when interior mutability is involved. For example, imagine `RefCell`
192194
//! would have a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`.
193-
//! This would be catastrophic, because it is possible to move out of a pinned
194-
//! `RefCell`: from `x: Pin<&mut RefCell<T>>`, use `let y = x.into_ref().get_ref()` to obtain
195-
//! `y: &RefCell<T>`, and from there use `y.borrow_mut().deref_mut()` to obtain `&mut T`
196-
//! which can be used with [`mem::swap`].
195+
//! Then we could do the following:
196+
//! ```ignore
197+
//! fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>) {
198+
//! { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T`
199+
//! let rc_shr: &RefCell<T> = rc.into_ref().get_ref();
200+
//! let b = rc_shr.borrow_mut();
201+
//! let content = &mut *b; // and here we have `&mut T` to the same data
202+
//! }
203+
//! ```
204+
//! This is catastrophic, it means we can first pin the content of the `RefCell`
205+
//! (using `RefCell::get_pin_mut`) and then move that content using the mutable
206+
//! reference we got later.
197207
//!
198208
//! On the other hand, if you decide *not* to offer any pinning projections, you
199209
//! are free to `impl<T> Unpin for Container<T>`. In the standard library,

0 commit comments

Comments
 (0)