|
177 | 177 | //! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`)
|
178 | 178 | //! have an operation with type `fn(Pin<&[mut] Wrapper<T>>) -> Pin<&[mut] T>`?
|
179 | 179 | //!
|
180 |
| -//! This question is closely related to the question of whether pinning is "structural". |
181 |
| -//! Structural pinning means that when you have pinned a wrapper type, the contents are |
182 |
| -//! also pinned. Structural pinning thus explains why pinning projections are correct. This means |
183 |
| -//! that if the type should have pinning projections for some fields, pinning must be structural |
184 |
| -//! for those fields. |
| 180 | +//! Having a pinning projection for some field means that pinning is "structural": |
| 181 | +//! when the wrapper is pinned, the field must be considered pinned, too. |
| 182 | +//! After all, the pinning projection lets us get a `Pin<&[mut] Field>`. |
185 | 183 | //!
|
186 |
| -//! In general, deciding for which fields pinning is structural (and thus for which fields |
187 |
| -//! pinning projections could be offered) is entirely up to the author of any given type. |
188 |
| -//! For many types, both answers are reasonable. For example, there could be a version |
189 |
| -//! of `Vec` with structural pinning and `get_pin`/`get_pin_mut` projections to access |
190 |
| -//! the `Vec` elements, and another version where the contents remain movable even when |
191 |
| -//! the `Vec` is pinned. |
192 |
| -//! |
193 |
| -//! However, structural pinning comes with a few extra requirements: |
| 184 | +//! However, structural pinning comes with a few extra requirements, so not all |
| 185 | +//! wrappers can be structural and hence not all wrappers can offer pinning projections: |
194 | 186 | //!
|
195 | 187 | //! 1. The wrapper must only be [`Unpin`] if all the structural fields are
|
196 | 188 | //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
|
|
214 | 206 | //! does not cause unsoundness.)
|
215 | 207 | //! 4. You must not offer any other operations that could lead to data being moved out of
|
216 | 208 | //! the fields when your type is pinned. For example, if the wrapper contains an
|
217 |
| -//! `Option<T>` and there is an operation such as `fn(Pin<&mut Wrapper<T>>) -> Option<T>`, |
218 |
| -//! that operation can be used to move a `T` out of a pinned `Wrapper` -- that means |
| 209 | +//! `Option<T>` and there is a `take`-like operation with type |
| 210 | +//! `fn(Pin<&mut Wrapper<T>>) -> Option<T>`, |
| 211 | +//! that operation can be used to move a `T` out of a pinned `Wrapper` -- which means |
219 | 212 | //! pinning cannot be structural.
|
220 | 213 | //!
|
221 | 214 | //! For a more complex example of moving data out of a pinnd type, imagine if `RefCell`
|
|
233 | 226 | //! (using `RefCell::get_pin_mut`) and then move that content using the mutable
|
234 | 227 | //! reference we got later.
|
235 | 228 | //!
|
236 |
| -//! On the other hand, if you decide *not* to offer any pinning projections, you |
237 |
| -//! do not have to do anything. If your type also does not do any pinning itself, |
238 |
| -//! you are free to `impl<T> Unpin for Wrapper<T>`. In the standard library, |
239 |
| -//! this is done for all pointer types: `Box<T>: Unpin` holds for all `T`. |
| 229 | +//! For a type like `Vec`, both possibilites (structural pinning or not) make sense, |
| 230 | +//! and the choice is up to the author. A `Vec` with structural pinning could |
| 231 | +//! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling |
| 232 | +//! `pop` on a pinned `Vec` because that would move the (structurally pinned) contents! |
| 233 | +//! Nor could it allow `push`, which might reallocate and thus also move the contents. |
| 234 | +//! A `Vec` without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents |
| 235 | +//! are never pinned and the `Vec` itself is fine with being moved as well. |
| 236 | +//! |
| 237 | +//! In the standard library, pointer types generally do not have structural pinning, |
| 238 | +//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`. |
240 | 239 | //! It makes sense to do this for pointer types, because moving the `Box<T>`
|
241 |
| -//! does not actually move the `T`: the `Box<T>` can be freely movable even if the `T` |
| 240 | +//! does not actually move the `T`: the `Box<T>` can be freely movable (aka `Unpin`) even if the `T` |
242 | 241 | //! is not. In fact, even `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves,
|
243 |
| -//! for the same reason. |
244 |
| -//! |
245 |
| -//! Another case where you might want to have a wrapper without structural pinning is when even |
246 |
| -//! a pinned wrapper lets its contents move, e.g. with a `take`-like operation. And, finally, |
247 |
| -//! if it is not possible to satisfy the requirements for structural pinning, it makes sense |
248 |
| -//! to add the `impl<T> Unpin for Wrapper<T>` to explicitly document this fact, and to let |
249 |
| -//! library clients benefit from the easier interaction with [`Pin`] that [`Unpin`] types enjoy. |
| 242 | +//! for the same reason: their contents (the `T`) are pinned, but the pointers themselves |
| 243 | +//! can be moved without moving the pinned data. For both `Box<T>` and `Pin<Box<T>>`, |
| 244 | +//! whether the content is pinned is entirely independent of whether the pointer is |
| 245 | +//! pinned, meaning pinning is *not* structural. |
250 | 246 | //!
|
251 | 247 | //! [`Pin`]: struct.Pin.html
|
252 | 248 | //! [`Unpin`]: ../../std/marker/trait.Unpin.html
|
|
0 commit comments