Skip to content

Commit c8f4efc

Browse files
committed
mention interaction with Deref in intro
1 parent c774bc6 commit c8f4efc

File tree

1 file changed

+38
-9
lines changed

1 file changed

+38
-9
lines changed

src/libcore/pin.rs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
//! obtain a `Box` or reference to pinned data, which implies that you cannot use
2020
//! operations such as [`mem::swap`]:
2121
//! ```
22+
//! use std::pin::Pin;
2223
//! fn swap_pins<T>(x: Pin<&mut T>, y: Pin<&mut T>) {
2324
//! // `mem::swap` needs `&mut T`, but we cannot get it.
2425
//! // We are stuck, we cannot swap the contents of these references.
@@ -32,6 +33,15 @@
3233
//! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being
3334
//! moved by making it impossible to call methods like [`mem::swap`] on them.
3435
//!
36+
//! [`Pin`] can be used to wrap any pointer type, and as such it interacts with
37+
//! [`Deref`] and [`DerefMut`]. A `Pin<P>` where `P: Deref` should be considered
38+
//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin<Box<T>>` is
39+
//! an owned pointer to a pinned `T`, and a `Pin<Rc<T>>` is a reference-counted
40+
//! pointer to a pinned `T`.
41+
//! For correctness, [`Pin`] relies on the [`Deref`] and [`DerefMut`] implementations
42+
//! to not move out of their `self` parameter, and to only ever return a pointer
43+
//! to pinned data when they are called on a pinned pointer.
44+
//!
3545
//! # `Unpin`
3646
//!
3747
//! However, these restrictions are usually not necessary. Many types are always freely
@@ -114,7 +124,7 @@
114124
//! list element will patch the pointers of its predecessor and successor to remove itself
115125
//! from the list.
116126
//!
117-
//! To make this work, it is crucial taht we can actually rely on `drop` being called.
127+
//! To make this work, it is crucial that we can actually rely on `drop` being called.
118128
//! And, in fact, this is a guarantee that `Pin` provides.
119129
//!
120130
//! # `Drop` guarantee
@@ -219,6 +229,8 @@
219229
//!
220230
//! [`Pin`]: struct.Pin.html
221231
//! [`Unpin`]: ../../std/marker/trait.Unpin.html
232+
//! [`Deref`]: ../../std/ops/trait.Deref.html
233+
//! [`DerefMut`]: ../../std/ops/trait.DerefMut.html
222234
//! [`mem::swap`]: ../../std/mem/fn.swap.html
223235
//! [`mem::forget`]: ../../std/mem/fn.forget.html
224236
//! [`Box`]: ../../std/boxed/struct.Box.html
@@ -319,16 +331,16 @@ impl<P: Deref> Pin<P> {
319331
/// Construct a new `Pin` around a reference to some data of a type that
320332
/// may or may not implement `Unpin`.
321333
///
334+
/// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
335+
/// instead.
336+
///
322337
/// # Safety
323338
///
324339
/// This constructor is unsafe because we cannot guarantee that the data
325340
/// pointed to by `pointer` is pinned, meaning that the data will not be moved or
326341
/// its storage invalidated until it gets dropped. If the constructed `Pin<P>` does
327342
/// not guarantee that the data `P` points to is pinned, constructing a
328-
/// `Pin<P>` is unsafe. In particular, calling `Pin::new_unchecked`
329-
/// on an `&'a mut T` is unsafe because while you are able to pin it for the given
330-
/// lifetime `'a`, you have no control over whether it is kept pinned once `'a`
331-
/// ends. A value, once pinned, must remain pinned forever (unless its type implements `Unpin`).
343+
/// `Pin<P>` is unsafe. In particular,
332344
///
333345
/// By using this method, you are making a promise about the `P::Deref` and
334346
/// `P::DerefMut` implementations, if they exist. Most importantly, they
@@ -340,21 +352,38 @@ impl<P: Deref> Pin<P> {
340352
/// must not be possible to obtain a `&mut P::Target` and then
341353
/// move out of that reference (using, for example [`mem::swap`]).
342354
///
343-
/// For example, the following is a *violation* of `Pin`'s safety:
355+
/// For example, calling `Pin::new_unchecked`
356+
/// on an `&'a mut T` is unsafe because while you are able to pin it for the given
357+
/// lifetime `'a`, you have no control over whether it is kept pinned once `'a` ends:
344358
/// ```
345359
/// use std::mem;
346360
/// use std::pin::Pin;
347361
///
348-
/// fn foo<T>(mut a: T, mut b: T) {
362+
/// fn move_pinned_ref<T>(mut a: T, mut b: T) {
349363
/// unsafe { let p = Pin::new_unchecked(&mut a); } // should mean `a` can never move again
350364
/// mem::swap(&mut a, &mut b);
351365
/// // the address of `a` changed to `b`'s stack slot, so `a` got moved even
352366
/// // though we have previously pinned it!
353367
/// }
354368
/// ```
369+
/// A value, once pinned, must remain pinned forever (unless its type implements `Unpin`).
355370
///
356-
/// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
357-
/// instead.
371+
/// Similarily, calling `Pin::new_unchecked` on a `Rc<T>` is unsafe because there could be
372+
/// aliases to the same data that are not subject to the pinning restrictions:
373+
/// ```
374+
/// use std::rc::Rc;
375+
/// use std::pin::Pin;
376+
///
377+
/// fn move_pinned_rc<T>(mut x: Rc<T>) {
378+
/// let pinned = unsafe { Pin::new_unchecked(x.clone()) };
379+
/// { let p: Pin<&T> = pinned.as_ref(); } // should mean the pointee can never move again
380+
/// drop(pinned);
381+
/// let content = Rc::get_mut(&mut x).unwrap();
382+
/// // Now, if `x` was the only reference, we have a mutable reference to
383+
/// // data that we pinned above, which we could use to move it as we have
384+
/// // seen in the previous example.
385+
/// }
386+
/// ```
358387
///
359388
/// [`mem::swap`]: ../../std/mem/fn.swap.html
360389
#[stable(feature = "pin", since = "1.33.0")]

0 commit comments

Comments
 (0)