|
174 | 174 | //! One interesting question arises when considering the interaction of pinning and
|
175 | 175 | //! the fields of a struct. When can a struct have a "pinning projection", i.e.,
|
176 | 176 | //! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`?
|
177 |
| -//! In a similar vein, when can a container type (such as `Vec`, `Box`, or `RefCell`) |
178 |
| -//! have an operation with type `fn(Pin<&[mut] Container<T>>) -> Pin<&[mut] T>`? |
| 177 | +//! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`) |
| 178 | +//! have an operation with type `fn(Pin<&[mut] Wrapper<T>>) -> Pin<&[mut] T>`? |
179 | 179 | //!
|
180 | 180 | //! This question is closely related to the question of whether pinning is "structural":
|
181 | 181 | //! when you have pinned a wrapper type, have you pinned its contents? Deciding this
|
182 |
| -//! is entirely up to the author of any given type. However, adding a |
183 |
| -//! projection to the API answers that question with a "yes" by offering pinned access |
184 |
| -//! to the contents. In that case, there are a couple requirements to be upheld: |
| 182 | +//! is entirely up to the author of any given type. For many types, both answers are reasonable |
| 183 | +//! (e.g., there could be a version of `Vec` with structural pinning and another |
| 184 | +//! version where the contents remain movable even when the `Vec` is pinned). |
| 185 | +//! If pinning is not structural, the wrapper can `impl<T> Unpin for Wrapper<T>`. |
| 186 | +//! If pinning is structural, the wrapper type can offer pinning projections. |
| 187 | +//! However, structural pinning comes with a few extra requirements: |
185 | 188 | //!
|
186 | 189 | //! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are
|
187 | 190 | //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
|
188 | 191 | //! the wrapper it is your responsibility *not* to add something like
|
189 |
| -//! `impl<T> Unpin for Container<T>`. (Notice that adding a projection operation |
| 192 | +//! `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation |
190 | 193 | //! requires unsafe code, so the fact that `Unpin` is a safe trait does not break
|
191 | 194 | //! the principle that you only have to worry about any of this if you use `unsafe`.)
|
192 | 195 | //! 2. The destructor of the wrapper must not move out of its argument. This is the exact
|
193 | 196 | //! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`,
|
194 | 197 | //! but the wrapper (and hence its fields) might have been pinned before.
|
195 | 198 | //! You have to guarantee that you do not move a field inside your `Drop` implementation.
|
196 |
| -//! 3. Your wrapper type must *not* be `#[repr(packed)]`. Packed structs have their fields |
197 |
| -//! moved around when they are dropped to properly align them, which is in conflict with |
198 |
| -//! claiming that the fields are pinned when your struct is. |
199 |
| -//! 4. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: |
| 199 | +//! In particular, as explained previously, this means that your wrapper type must *not* |
| 200 | +//! be `#[repr(packed)]`. |
| 201 | +//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: |
200 | 202 | //! once your wrapper is pinned, the memory that contains the
|
201 | 203 | //! content is not overwritten or deallocated without calling the content's destructors.
|
202 | 204 | //! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail
|
203 | 205 | //! to call `drop` on all elements if one of the destructors panics. This violates the
|
204 | 206 | //! `Drop` guarantee, because it can lead to elements being deallocated without
|
205 | 207 | //! their destructor being called. (`VecDeque` has no pinning projections, so this
|
206 | 208 | //! does not cause unsoundness.)
|
207 |
| -//! 5. You must not offer any other operations that could lead to data being moved out of |
| 209 | +//! 4. You must not offer any other operations that could lead to data being moved out of |
208 | 210 | //! the fields when your type is pinned. This is usually not a concern, but can become
|
209 | 211 | //! tricky when interior mutability is involved. For example, imagine if `RefCell`
|
210 | 212 | //! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`.
|
|
222 | 224 | //! reference we got later.
|
223 | 225 | //!
|
224 | 226 | //! On the other hand, if you decide *not* to offer any pinning projections, you
|
225 |
| -//! are free to `impl<T> Unpin for Container<T>`. In the standard library, |
| 227 | +//! do not have to do anything. If your type also does not do any pinning itself, |
| 228 | +//! you are free to `impl<T> Unpin for Wrapper<T>`. In the standard library, |
226 | 229 | //! this is done for all pointer types: `Box<T>: Unpin` holds for all `T`.
|
227 | 230 | //! It makes sense to do this for pointer types, because moving the `Box<T>`
|
228 | 231 | //! does not actually move the `T`: the `Box<T>` can be freely movable even if the `T`
|
229 | 232 | //! is not. In fact, even `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves,
|
230 | 233 | //! for the same reason.
|
231 | 234 | //!
|
| 235 | +//! Another case where you might want to have a wrapper without structural pinning is when even |
| 236 | +//! a pinned wrapper lets its contents move, e.g. with a `take`-like operation. And, finally, |
| 237 | +//! if it is not possible to satisfy the requirements for structural pinning, it makes sense |
| 238 | +//! to add the `impl<T> Unpin for Wrapper<T>` to explicitly document this fact, and to let |
| 239 | +//! library clients benefit from the easier interaction with [`Pin`] that [`Unpin`] types enjoy. |
| 240 | +//! |
232 | 241 | //! [`Pin`]: struct.Pin.html
|
233 | 242 | //! [`Unpin`]: ../../std/marker/trait.Unpin.html
|
234 | 243 | //! [`Deref`]: ../../std/ops/trait.Deref.html
|
|
0 commit comments