|
25 | 25 | //! values.
|
26 | 26 | //!
|
27 | 27 | //! It is worth reiterating that [`Pin`] does *not* change the fact that a Rust compiler
|
28 |
| -//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` |
| 28 | +//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` |
29 | 29 | //! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being
|
30 |
| -//! moved by making it impossible to call methods like [`mem::swap`] on them. |
| 30 | +//! moved by making it impossible to call methods like [`mem::swap`] on them. These |
| 31 | +//! methods all need an `&mut T`, and you cannot obtain that from a `Pin`. |
31 | 32 | //!
|
32 | 33 | //! # `Unpin`
|
33 | 34 | //!
|
|
42 | 43 | //! `Unpin` has no effect on the behavior of `Pin<Box<T>>` (here, `T` is the
|
43 | 44 | //! pointed-to type).
|
44 | 45 | //!
|
45 |
| -//! # Examples |
| 46 | +//! # Example: Self-referential struct |
46 | 47 | //!
|
47 | 48 | //! ```rust
|
48 | 49 | //! use std::pin::Pin;
|
|
97 | 98 | //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
|
98 | 99 | //! ```
|
99 | 100 | //!
|
| 101 | +//! # Example: intrusive doubly-linked list |
| 102 | +//! |
| 103 | +//! In an intrusive doubly-linked list, the collection does not actually allocate |
| 104 | +//! the memory for the elements itself. Allocation is controlled by the clients, |
| 105 | +//! and elements can live on a stack frame that lives shorter than the collection does. |
| 106 | +//! |
| 107 | +//! To make this work, every element has pointers to its predecessor and successor in |
| 108 | +//! the list. Element can only be added when they are pinned, because moving the elements |
| 109 | +//! around would invalidate the pointers. Moreover, the `Drop` implementation of a linked |
| 110 | +//! list element will patch the pointers of its predecessor and successor to remove itself |
| 111 | +//! from the list. |
| 112 | +//! |
| 113 | +//! To make this work, it is crucial taht we can actually rely on `drop` being called. |
| 114 | +//! And, in fact, this is a guarantee that `Pin` provides. |
| 115 | +//! |
100 | 116 | //! # `Drop` guarantee
|
101 | 117 | //!
|
102 | 118 | //! The purpose of pinning is to be able to rely on the placement of some data in memory.
|
|
108 | 124 | //! replacing a `Some(v)` by `None`, or calling `Vec::set_len` to "kill" some elements
|
109 | 125 | //! off of a vector.
|
110 | 126 | //!
|
111 |
| -//! The purpose of this guarantee is to allow data structures that store pointers |
112 |
| -//! to pinned data. For example, in an intrusive doubly-linked list, every element |
113 |
| -//! has pointers to its predecessor and successor in the list. Every element |
114 |
| -//! must also be pinned, because moving the elements around would invalidate the pointers. |
115 |
| -//! Moreover, the `Drop` implementation of a linked list element will patch the pointers |
116 |
| -//! of its predecessor and successor to remove itself from the list. Clearly, if an element |
117 |
| -//! could be deallocated or overwritten without calling `drop`, the pointers into it |
| 127 | +//! This is exactly the kind of guarantee that the intrusive linked list from the previous |
| 128 | +//! section needs to function correctly. Clearly, if an element |
| 129 | +//! could be deallocated or otherwise invalidated without calling `drop`, the pointers into it |
118 | 130 | //! from its neighbouring elements would become invalid, which would break the data structure.
|
119 | 131 | //!
|
120 | 132 | //! Notice that this guarantee does *not* mean that memory does not leak! It is still
|
121 | 133 | //! completely okay not to ever call `drop` on a pinned element (e.g., you can still
|
122 |
| -//! call [`mem::forget`] on a `Pin<Box<T>>`). However you may *not* then free or reuse the storage |
123 |
| -//! without calling `drop`. |
| 134 | +//! call [`mem::forget`] on a `Pin<Box<T>>`). In the example of the doubly-linked |
| 135 | +//! list, that element would just stay in the list. However you may not free or reuse the storage |
| 136 | +//! *without calling `drop`*. |
124 | 137 | //!
|
125 | 138 | //! # `Drop` implementation
|
126 | 139 | //!
|
127 |
| -//! If your type relies on pinning (for example, because it contains internal |
128 |
| -//! references, or because you are implementing something like the intrusive |
129 |
| -//! doubly-linked list mentioned in the previous section), you have to be careful |
| 140 | +//! If your type uses pinning (such as the two examples above), you have to be careful |
130 | 141 | //! when implementing `Drop`. The `drop` function takes `&mut self`, but this
|
131 | 142 | //! is called *even if your type was previously pinned*! It is as if the
|
132 |
| -//! compiler automatically called `get_unchecked_mut`. This can never cause |
133 |
| -//! a problem in safe code because implementing a type that relies on pinning |
| 143 | +//! compiler automatically called `get_unchecked_mut`. |
| 144 | +//! |
| 145 | +//! This can never cause a problem in safe code because implementing a type that relies on pinning |
134 | 146 | //! requires unsafe code, but be aware that deciding to make use of pinning
|
135 | 147 | //! in your type (for example by implementing some operation on `Pin<&[mut] Self>`)
|
136 | 148 | //! has consequences for your `Drop` implementation as well: if an element
|
|
139 | 151 | //!
|
140 | 152 | //! # Projections and Structural Pinning
|
141 | 153 | //!
|
142 |
| -//! One interesting question arises when considering pinning and "container types" -- |
143 |
| -//! types such as `Vec`, `Box`, or `RefCell`; types that serve as wrappers |
144 |
| -//! around other types. When can such a type have a "projection" operation, an |
145 |
| -//! operation with type `fn(Pin<&[mut] Container<T>>) -> Pin<&[mut] T>`? |
146 |
| -//! This does not just apply to generic container types, even for normal structs |
147 |
| -//! the question arises whether `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>` |
148 |
| -//! is an operation that can be soundly added to the API. |
| 154 | +//! 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., |
| 156 | +//! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`? |
| 157 | +//! In a similar vein, when can a container type (such as `Vec`, `Box`, or `RefCell`) |
| 158 | +//! have an operation with type `fn(Pin<&[mut] Container<T>>) -> Pin<&[mut] T>`? |
149 | 159 | //!
|
150 | 160 | //! This question is closely related to the question of whether pinning is "structural":
|
151 |
| -//! when you have pinned a container, have you pinned its contents? Adding a |
| 161 | +//! when you have pinned a wrapper type, have you pinned its contents? Adding a |
152 | 162 | //! projection to the API answers that question with a "yes" by offering pinned access
|
153 | 163 | //! to the contents.
|
154 | 164 | //!
|
155 | 165 | //! In general, as the author of a type you get to decide whether pinning is structural, and
|
156 | 166 | //! whether projections are provided. However, there are a couple requirements to be
|
157 | 167 | //! upheld when adding projection operations:
|
158 | 168 | //!
|
159 |
| -//! 1. The container must only be [`Unpin`] if all the fields one can project to are |
| 169 | +//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are |
160 | 170 | //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
|
161 |
| -//! the container it is your responsibility *not* to add something like |
| 171 | +//! the wrapper it is your responsibility *not* to add something like |
162 | 172 | //! `impl<T> Unpin for Container<T>`. (Notice that adding a projection operation
|
163 | 173 | //! requires unsafe code, so the fact that `Unpin` is a safe trait does not break
|
164 | 174 | //! the principle that you only have to worry about any of this if you use `unsafe`.)
|
165 |
| -//! 2. The destructor of the container must not move out of its argument. This is the exact |
| 175 | +//! 2. The destructor of the wrapper must not move out of its argument. This is the exact |
166 | 176 | //! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`,
|
167 |
| -//! but the container (and hence its fields) might have been pinned before. |
| 177 | +//! but the wrapper (and hence its fields) might have been pinned before. |
168 | 178 | //! You have to guarantee that you do not move a field inside your `Drop` implementation.
|
169 |
| -//! 3. Your container type must *not* be `#[repr(packed)]`. Packed structs have their fields |
| 179 | +//! 3. Your wrapper type must *not* be `#[repr(packed)]`. Packed structs have their fields |
170 | 180 | //! moved around when they are dropped to properly align them, which is in conflict with
|
171 | 181 | //! claiming that the fields are pinned when your struct is.
|
172 | 182 | //! 4. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]:
|
173 |
| -//! once your container is pinned, the memory that contains the |
| 183 | +//! once your wrapper is pinned, the memory that contains the |
174 | 184 | //! content is not overwritten or deallocated without calling the content's destructors.
|
175 | 185 | //! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail
|
176 | 186 | //! to call `drop` on all elements if one of the destructors panics. This violates the
|
|
0 commit comments